commit 8796473f1fd3cd594fce0303bc119e2b00fd4bae parent 475618382a9741af99dc906cf94a6de257cb2dd3 Author: Casaburi Johannes <johannes.casaburi@students.bfh.ch> Date: Tue, 16 Apr 2024 21:54:09 +0200 renamed some files Diffstat:
14 files changed, 600 insertions(+), 717 deletions(-)
diff --git a/src/donau/Makefile.am b/src/donau/Makefile.am @@ -43,18 +43,16 @@ donau_httpd_SOURCES = \ donau-httpd_db.c donau-httpd_db.h \ donau-httpd_keys.c donau-httpd_keys.h \ donau-httpd_config.c donau-httpd_config.h \ - donau-httpd_get-charities.c donau_httpd_charity.h \ + donau-httpd_charities_get.c donau_httpd_charity.h \ donau-httpd_charity_delete.c \ - donau-httpd_get-charity.c donau-httpd_post-charity.c \ - donau-httpd_get-history.c \ - donau-httpd_post-submit-receipts.c donau_httpd_submit-receipts.h \ + donau-httpd_charity_get.c donau-httpd_charity_insert.c \ + donau-httpd_history_get.c \ + donau-httpd_batch-submit.c donau_httpd_batch-submit.h \ donau-httpd_terms.c donau-httpd_terms.h \ - donau-httpd_post-batch-issue.c donau_httpd_batch-issue.h + donau-httpd_batch-issue.c donau_httpd_batch-issue.h # Testcases -AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; - check_SCRIPTS = \ test_donau_httpd.sh if HAVE_EXPENSIVE_TESTS @@ -69,7 +67,6 @@ TESTS = \ # Distribution EXTRA_DIST = \ - test_donau_httpd_home/.local/share/taler/donau/offline-keys/master.priv \ test_donau_httpd.conf \ test_donau_unix.conf \ test_donau_httpd.get \ diff --git a/src/donau/donau-httpd.c b/src/donau/donau-httpd.c @@ -33,7 +33,7 @@ #include "donau-httpd_keys.h" #include "donau-httpd_charity.h" #include "donau-httpd_batch-issue.h" -#include "donau-httpd_submit-receipts.h" +#include "donau-httpd_batch-submit.h" #include "donau-httpd_history.h" #include "donau-httpd_terms.h" #include "donaudb_plugin.h" diff --git a/src/donau/donau-httpd_batch-issue.c b/src/donau/donau-httpd_batch-issue.c @@ -0,0 +1,396 @@ +/* + 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 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 donau-httpd_batch-issue.c + * @brief Handle request to issue receipts. + * @author Lukas Matyja + */ +#include <taler/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/taler_json_lib.h> +#include <taler/taler_mhd_lib.h> +#include <taler/taler_signatures.h> +#include "donaudb_plugin.h" +#include "donau-httpd_batch-issue.h" +#include "donau-httpd_db.h" +#include "donau-httpd_metrics.h" +#include "donau_json_lib.h" +#include "donau-httpd_keys.h" + + +/** + * Parse a bkp encoded in JSON. + * + * @param[out] bkp where to return the result + * @param bkp_key_obj json to parse + * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if @a bkp_key_obj + * is malformed. + */ +static enum GNUNET_GenericReturnValue +parse_json_bkp (struct DONAU_BlindedUniqueDonationIdentifierKeyPair *bkp, + const json_t *bkp_key_obj) +{ + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("h_du_pub", + &bkp->h_donation_unit_pub), + DONAU_JSON_spec_blinded_donation_identifier ("blinded_udi", + &bkp->blinded_udi), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (bkp_key_obj, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + /* TODO: Check for duplicate blinded UDIs.*/ + return GNUNET_OK; +} + + +/** + * Parse signatures to JSON. + * + * @param num_sig number of signatures + * @param signatures + * @param[out] j_signatures JSON object + * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if we could not parse + * is malformed. + */ +static void +signatures_to_JSON (const size_t num_sig, + struct DONAU_BlindedDonationUnitSignature*signatures, + json_t *j_signatures) +{ + for (size_t i = 0; i < num_sig; i++) + { + struct DONAU_BlindedDonationUnitSignature*signature = &signatures[i]; + GNUNET_assert ( + 0 == json_array_append ( + j_signatures, + GNUNET_JSON_PACK ( + DONAU_JSON_pack_blinded_donation_unit_sig ("blinded_signatures", + signature)))); + } +} + + +MHD_RESULT +DH_handler_issue_receipts_post (struct DH_RequestContext *rc, + const json_t *root, + const char *const args[1]) +{ + struct DONAU_CharitySignatureP charity_sig; + uint64_t year; + bool second_time = false; + unsigned long long charity_id; + char dummy; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "issue receipts request! \n"); + + if ( (NULL == args[0]) || + (1 != sscanf (args[0], + "%llu%c", + &charity_id, + &dummy)) ) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "charity_id"); + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "issue receipts for charity id: %llu\n", + charity_id); + + const json_t *budikeypairs; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_array_const ("budikeypairs", + &budikeypairs), + GNUNET_JSON_spec_fixed_auto ("charity_sig", + &charity_sig), + GNUNET_JSON_spec_uint64 ("year", + &year), + GNUNET_JSON_spec_end () + }; + + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (rc->connection, + root, + spec); + if (GNUNET_SYSERR == res) + return MHD_NO; /* hard failure */ + if (GNUNET_NO == res) + { + GNUNET_break_op (0); + return MHD_YES; /* failure */ + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "parse some values!\n"); + /* parse the budikeypairs array */ + const size_t num_bkps + = json_array_size (budikeypairs); + struct DONAU_BlindedUniqueDonationIdentifierKeyPair *bkps; + if (0 != num_bkps) + { + json_t *bkp_obj; + size_t index; + + + bkps = GNUNET_new_array + (num_bkps, + struct DONAU_BlindedUniqueDonationIdentifierKeyPair); + json_array_foreach (budikeypairs, index, bkp_obj) + { + if (GNUNET_SYSERR == + parse_json_bkp (&bkps[index], bkp_obj)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "budikeypairs"); + } + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "empty array of budi key pairs!\n"); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "budikeypairs"); + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "budi key pairs array is parsed!\n"); + // Get charity pub + struct DONAUDB_CharityMetaData charity_meta; + enum GNUNET_DB_QueryStatus qs_charity; + + qs_charity = DH_plugin->lookup_charity (DH_plugin->cls, + (uint64_t) charity_id, + &charity_meta); + switch (qs_charity) + { + 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: + return TALER_MHD_reply_with_error ( + rc->connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_DONAU_CHARITY_NOT_FOUND, + NULL); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "got charity from db!\n"); + /* verify charity signature */ + if (GNUNET_OK != + DONAU_charity_bkp_verify (num_bkps, + bkps, + &charity_meta.charity_pub, + &charity_sig)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error ( + rc->connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_DONAU_CHARITY_SIGNATURE_INVALID, + NULL); + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "charity signature valid!\n"); + /* request already made? -> idempotent */ + enum GNUNET_DB_QueryStatus qs_check_receipts; + struct DONAUDB_IssuedReceiptsMetaData check_receipts_meta; + struct DONAU_DonationReceiptHashP h_receipts = {0}; + json_t *blind_signatures = json_array (); + GNUNET_assert (NULL != blind_signatures); + + struct GNUNET_HashContext *hc; + hc = GNUNET_CRYPTO_hash_context_start (); + for (unsigned int i = 0; i < num_bkps; i++) + { + GNUNET_CRYPTO_hash_context_read (hc, + &bkps[i].h_donation_unit_pub, + sizeof (bkps[i].h_donation_unit_pub)); + GNUNET_CRYPTO_hash_context_read (hc, + bkps[i].blinded_udi.blinded_message, + sizeof (bkps[i].blinded_udi.blinded_message + )); + } + GNUNET_CRYPTO_hash_context_read (hc, + &charity_sig, + sizeof (struct DONAU_CharitySignatureP)); + GNUNET_CRYPTO_hash_context_read (hc, + &year, + sizeof (uint64_t)); + GNUNET_CRYPTO_hash_context_finish (hc, + &h_receipts.hash); + +start: + qs_check_receipts = DH_plugin->lookup_issued_receipts (DH_plugin->cls, + &h_receipts, + &check_receipts_meta); + switch (qs_check_receipts) + { + 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_log (GNUNET_ERROR_TYPE_INFO, + "request has not been made yet (first time)!\n"); + break; // it's the first request from the charity, we can proceed + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "request has been made already!\n"); + signatures_to_JSON (num_bkps, check_receipts_meta.blinded_sig, + blind_signatures); + return TALER_MHD_REPLY_JSON_PACK ( + rc->connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("blind_signatures", + blind_signatures)); + } + /* calculate new receipts to date and check annual limit */ + struct TALER_Amount receipts_sum; + + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (DH_currency, + &receipts_sum)); + for (size_t i = 0; i < num_bkps; i++) + { + struct DH_DonationUnitKey *dk; + + if (NULL == (dk = DH_keys_donation_unit_by_hash ( + &bkps[i].h_donation_unit_pub))) + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_DONAU_GENERIC_KEYS_MISSING, + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "public key value: %lu.%u\n", + dk->value.value, dk->value.fraction); + GNUNET_assert (0 <= TALER_amount_add (&receipts_sum, + &receipts_sum, + &dk->value)); + } + struct TALER_Amount new_receipts_to_date; + + TALER_amount_add (&new_receipts_to_date, + &receipts_sum, + &charity_meta.receipts_to_date); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "new_receipts_to_date: %lu.%u, receipts_sum: %lu.%u, charity_max_per_year: %lu.%u\n", + new_receipts_to_date.value, new_receipts_to_date.fraction, + receipts_sum.value, + receipts_sum.fraction, charity_meta.max_per_year.value, + charity_meta.max_per_year.fraction); + // new_receipts_to_date has to be smaller or equal as max_per_year + if (0 < TALER_amount_cmp (&new_receipts_to_date, &charity_meta.max_per_year)) + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_DONAU_EXCEEDING_DONATION_LIMIT, + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "calculated the new receipts to date amount\n"); + + /* sign budis and send the signatures back */ + struct DONAU_BlindedDonationUnitSignature du_sigs[num_bkps]; + struct BUDIKeyPair_sign_data bkps_sign_data[num_bkps]; + + for (int i = 0; i < num_bkps; i++) + { + bkps_sign_data[i].h_donation_unit_pub = &bkps[i].h_donation_unit_pub; + bkps_sign_data[i].budi = &bkps[i].blinded_udi; + } + if (TALER_EC_NONE != DH_keys_donation_unit_batch_sign (num_bkps, + bkps_sign_data, + du_sigs)) + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, // TODO:other EC + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "made blind signatures!\n"); + /* save new receipts to date and save receipts Request (blinded signatures, + * charity id, amount, hash over bkps) to make it idempotent*/ + enum GNUNET_DB_QueryStatus qs_insert_ir; + qs_insert_ir = DH_plugin->insert_issued_receipt ( + DH_plugin->cls, + num_bkps, + du_sigs, + (uint64_t) charity_id, + &h_receipts, + &receipts_sum, + &new_receipts_to_date); + switch (qs_insert_ir) + { + 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_assert (! second_time); + second_time = true; + goto start; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "issue receipts request is saved! (idempotent)\n"); + + signatures_to_JSON (num_bkps, du_sigs, blind_signatures); + return TALER_MHD_REPLY_JSON_PACK ( + rc->connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("blind_signatures", + blind_signatures)); +} + + +/* end of donau-httpd_post-batch-issue.c */ diff --git a/src/donau/donau-httpd_batch-issue.h b/src/donau/donau-httpd_batch-issue.h @@ -18,8 +18,8 @@ * @brief Handle /batch-issue requests * @author Lukas Matyja */ -#ifndef DONAU_HTTPD_ISSUE_RECEIPTS_H -#define DONAU_HTTPD_ISSUE_RECEIPTS_H +#ifndef DONAU_HTTPD_BATCH_ISSUE_H +#define DONAU_HTTPD_BATCH_ISSUE_H #include <microhttpd.h> #include "donau-httpd.h" diff --git a/src/donau/donau-httpd_batch-submit.c b/src/donau/donau-httpd_batch-submit.c @@ -0,0 +1,155 @@ +/* + 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 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 donau-httpd_batch-submit.c + * @brief Handle request to insert a submitted receipt. + * @author Johannes Casaburi + */ +#include "taler/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/taler_json_lib.h" +#include "taler/taler_mhd_lib.h" +#include "taler/taler_signatures.h" +#include "donaudb_plugin.h" +#include "donau-httpd_batch-submit.h" +#include "donau-httpd_db.h" +#include "donau-httpd_metrics.h" + + +/** + * Closure for #insert_submitted_receipt() + */ +struct InsertReceiptContext +{ + struct DONAU_HashDonorTaxId *h_tax_number; + union GNUNET_CRYPTO_BlindSessionNonce *nonce; + struct DONAU_DonationUnitPublicKey *donation_unit_pub; + struct DONAU_DonauSignatureP *donau_sig; + uint64_t donation_year; +}; + + +/** + * Function implementing insert submit-receipt transaction. + * + * Runs the transaction logic; IF it returns a non-error code, the + * transaction logic MUST NOT queue a MHD response. IF it returns an hard + * error, the transaction logic MUST queue a MHD response and set @a mhd_ret. + * IF it returns the soft error code, the function MAY be called again to + * retry and MUST not queue a MHD response. + * + * @param cls closure with a `struct InsertReceiptContext` + * @param connection MHD request which triggered the transaction + * @param[out] mhd_ret set to MHD response status for @a connection, + * if transaction failed (!) + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +insert_submitted_receipt (void *cls, + struct MHD_Connection *connection, + MHD_RESULT *mhd_ret) +{ + struct InsertReceiptContext *irc = cls; + enum GNUNET_DB_QueryStatus qs; + + qs = DH_plugin->insert_submitted_receipt (DH_plugin->cls, + irc->h_tax_number, + irc->nonce, + irc->donation_unit_pub, + irc->donau_sig, + irc->donation_year); + if (qs <= 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + { + GNUNET_break (0); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert_submitted_receipt"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + return qs; + } + + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +} + + +MHD_RESULT +DH_handler_submit_receipts_post (struct DH_RequestContext *rc, + const json_t *root, + const char *const args[]) +{ + struct InsertReceiptContext irc; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("h_tax_number", + &irc.h_tax_number), + GNUNET_JSON_spec_fixed_auto ("nonce", + &irc.nonce), + GNUNET_JSON_spec_fixed_auto ("donation_unit_pub", + &irc.donation_unit_pub), + GNUNET_JSON_spec_fixed_auto ("donau_sig", + &irc.donau_sig), + GNUNET_JSON_spec_uint64 ("donation_year", + &irc.donation_year), + GNUNET_JSON_spec_end () + }; + + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (rc->connection, + root, + spec); + if (GNUNET_SYSERR == res) + return MHD_NO; /* hard failure */ + if (GNUNET_NO == res) + { + GNUNET_break_op (0); + return MHD_YES; /* failure */ + } + } + + { + MHD_RESULT mhd_ret; + + if (GNUNET_OK != + DH_DB_run_transaction (rc->connection, + "insert_submitted_receipt", + DH_MT_REQUEST_OTHER, + &mhd_ret, + &insert_submitted_receipt, + &irc)) + { + return mhd_ret; + } + } + return TALER_MHD_reply_static ( + rc->connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +/* end of donau-httpd_post-submit-receipts.c */ diff --git a/src/donau/donau-httpd_batch-submit.h b/src/donau/donau-httpd_batch-submit.h @@ -0,0 +1,41 @@ +/* + 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 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 donau-httpd_submit-receipts.h + * @brief Handle /submit requests + * @author Johannes Casaburi + */ +#ifndef DONAU_HTTPD_BATCH_SUBMIT_H +#define DONAU_HTTPD_BATCH_SUBMIT_H + +#include <microhttpd.h> +#include "donau-httpd.h" + + +/** + * Handle a POST "/submit" request. + * + * @param connection the MHD connection to handle + * @param root uploaded JSON data + * @return MHD result code + */ +MHD_RESULT +DH_handler_submit_receipts_post ( + struct DH_RequestContext *rc, + const json_t *root, + const char *const args[]); + +#endif diff --git a/src/donau/donau-httpd_get-charities.c b/src/donau/donau-httpd_charities_get.c diff --git a/src/donau/donau-httpd_get-charity.c b/src/donau/donau-httpd_charity_get.c diff --git a/src/donau/donau-httpd_post-charity.c b/src/donau/donau-httpd_charity_insert.c diff --git a/src/donau/donau-httpd_get-history-entry.c b/src/donau/donau-httpd_get-history-entry.c @@ -1,114 +0,0 @@ -/* - 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 donau-httpd_history-get.c - * @brief Return summary information about AML decision - * @author Johannes Casaburi - */ -#include "taler/platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler/taler_json_lib.h" -#include "taler/taler_mhd_lib.h" -#include "taler/taler_signatures.h" -#include "donaudb_plugin.h" -#include "donau-httpd_history.h" -// #include "donau-httpd.h" -// #include "donau-httpd_metrics.h" - - -/** - * Maximum number of records we return per request. - */ -#define MAX_RECORDS 1024 - -MHD_RESULT -DH_handler_history_entry_get ( - struct DH_RequestContext *rc, - const char *const args[]) -{ - unsigned long long charity_id; - char dummy; - - if ( (NULL == args[0]) || - (1 != sscanf (args[0], - "%llu%c", - &charity_id, - &dummy)) ) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "charity_id"); - } - - if (NULL != args[1]) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_ENDPOINT_UNKNOWN, - args[1]); - } - - { - struct TALER_Amount final_amount; - uint64_t donation_year; - enum GNUNET_DB_QueryStatus qs; - MHD_RESULT result; - - qs = DH_plugin->lookup_history_entry (DH_plugin->cls, - charity_id, - &final_amount, - donation_year); - 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: - return TALER_MHD_reply_static ( - rc->connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - - result = TALER_MHD_REPLY_JSON_PACK ( - rc->connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("final_amount", - &final_amount), - GNUNET_JSON_pack_uint64 ("donation_year", - donation_year)); - - return result; - } -} - - -/* end of donau-httpd_aml-decision_get.c */ diff --git a/src/donau/donau-httpd_get-history.c b/src/donau/donau-httpd_history_get.c diff --git a/src/donau/donau-httpd_post-batch-issue.c b/src/donau/donau-httpd_post-batch-issue.c @@ -1,396 +0,0 @@ -/* - 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 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 donau-httpd_post-batch-issue.c - * @brief Handle request to issue receipts. - * @author Lukas Matyja - */ -#include <taler/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/taler_json_lib.h> -#include <taler/taler_mhd_lib.h> -#include <taler/taler_signatures.h> -#include "donaudb_plugin.h" -#include "donau-httpd_batch-issue.h" -#include "donau-httpd_db.h" -#include "donau-httpd_metrics.h" -#include "donau_json_lib.h" -#include "donau-httpd_keys.h" - - -/** - * Parse a bkp encoded in JSON. - * - * @param[out] bkp where to return the result - * @param bkp_key_obj json to parse - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if @a bkp_key_obj - * is malformed. - */ -static enum GNUNET_GenericReturnValue -parse_json_bkp (struct DONAU_BlindedUniqueDonationIdentifierKeyPair *bkp, - const json_t *bkp_key_obj) -{ - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("h_du_pub", - &bkp->h_donation_unit_pub), - DONAU_JSON_spec_blinded_donation_identifier ("blinded_udi", - &bkp->blinded_udi), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (bkp_key_obj, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* TODO: Check for duplicate blinded UDIs.*/ - return GNUNET_OK; -} - - -/** - * Parse signatures to JSON. - * - * @param num_sig number of signatures - * @param signatures - * @param[out] j_signatures JSON object - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if we could not parse - * is malformed. - */ -static void -signatures_to_JSON (const size_t num_sig, - struct DONAU_BlindedDonationUnitSignature*signatures, - json_t *j_signatures) -{ - for (size_t i = 0; i < num_sig; i++) - { - struct DONAU_BlindedDonationUnitSignature*signature = &signatures[i]; - GNUNET_assert ( - 0 == json_array_append ( - j_signatures, - GNUNET_JSON_PACK ( - DONAU_JSON_pack_blinded_donation_unit_sig ("blinded_signatures", - signature)))); - } -} - - -MHD_RESULT -DH_handler_issue_receipts_post (struct DH_RequestContext *rc, - const json_t *root, - const char *const args[1]) -{ - struct DONAU_CharitySignatureP charity_sig; - uint64_t year; - bool second_time = false; - unsigned long long charity_id; - char dummy; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "issue receipts request! \n"); - - if ( (NULL == args[0]) || - (1 != sscanf (args[0], - "%llu%c", - &charity_id, - &dummy)) ) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "charity_id"); - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "issue receipts for charity id: %llu\n", - charity_id); - - const json_t *budikeypairs; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("budikeypairs", - &budikeypairs), - GNUNET_JSON_spec_fixed_auto ("charity_sig", - &charity_sig), - GNUNET_JSON_spec_uint64 ("year", - &year), - GNUNET_JSON_spec_end () - }; - - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (rc->connection, - root, - spec); - if (GNUNET_SYSERR == res) - return MHD_NO; /* hard failure */ - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - return MHD_YES; /* failure */ - } - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "parse some values!\n"); - /* parse the budikeypairs array */ - const size_t num_bkps - = json_array_size (budikeypairs); - struct DONAU_BlindedUniqueDonationIdentifierKeyPair *bkps; - if (0 != num_bkps) - { - json_t *bkp_obj; - size_t index; - - - bkps = GNUNET_new_array - (num_bkps, - struct DONAU_BlindedUniqueDonationIdentifierKeyPair); - json_array_foreach (budikeypairs, index, bkp_obj) - { - if (GNUNET_SYSERR == - parse_json_bkp (&bkps[index], bkp_obj)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "budikeypairs"); - } - } - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "empty array of budi key pairs!\n"); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "budikeypairs"); - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "budi key pairs array is parsed!\n"); - // Get charity pub - struct DONAUDB_CharityMetaData charity_meta; - enum GNUNET_DB_QueryStatus qs_charity; - - qs_charity = DH_plugin->lookup_charity (DH_plugin->cls, - (uint64_t) charity_id, - &charity_meta); - switch (qs_charity) - { - 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: - return TALER_MHD_reply_with_error ( - rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_DONAU_CHARITY_NOT_FOUND, - NULL); - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "got charity from db!\n"); - /* verify charity signature */ - if (GNUNET_OK != - DONAU_charity_bkp_verify (num_bkps, - bkps, - &charity_meta.charity_pub, - &charity_sig)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error ( - rc->connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_DONAU_CHARITY_SIGNATURE_INVALID, - NULL); - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "charity signature valid!\n"); - /* request already made? -> idempotent */ - enum GNUNET_DB_QueryStatus qs_check_receipts; - struct DONAUDB_IssuedReceiptsMetaData check_receipts_meta; - struct DONAU_DonationReceiptHashP h_receipts = {0}; - json_t *blind_signatures = json_array (); - GNUNET_assert (NULL != blind_signatures); - - struct GNUNET_HashContext *hc; - hc = GNUNET_CRYPTO_hash_context_start (); - for (unsigned int i = 0; i < num_bkps; i++) - { - GNUNET_CRYPTO_hash_context_read (hc, - &bkps[i].h_donation_unit_pub, - sizeof (bkps[i].h_donation_unit_pub)); - GNUNET_CRYPTO_hash_context_read (hc, - bkps[i].blinded_udi.blinded_message, - sizeof (bkps[i].blinded_udi.blinded_message - )); - } - GNUNET_CRYPTO_hash_context_read (hc, - &charity_sig, - sizeof (struct DONAU_CharitySignatureP)); - GNUNET_CRYPTO_hash_context_read (hc, - &year, - sizeof (uint64_t)); - GNUNET_CRYPTO_hash_context_finish (hc, - &h_receipts.hash); - -start: - qs_check_receipts = DH_plugin->lookup_issued_receipts (DH_plugin->cls, - &h_receipts, - &check_receipts_meta); - switch (qs_check_receipts) - { - 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_log (GNUNET_ERROR_TYPE_INFO, - "request has not been made yet (first time)!\n"); - break; // it's the first request from the charity, we can proceed - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "request has been made already!\n"); - signatures_to_JSON (num_bkps, check_receipts_meta.blinded_sig, - blind_signatures); - return TALER_MHD_REPLY_JSON_PACK ( - rc->connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ("blind_signatures", - blind_signatures)); - } - /* calculate new receipts to date and check annual limit */ - struct TALER_Amount receipts_sum; - - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (DH_currency, - &receipts_sum)); - for (size_t i = 0; i < num_bkps; i++) - { - struct DH_DonationUnitKey *dk; - - if (NULL == (dk = DH_keys_donation_unit_by_hash ( - &bkps[i].h_donation_unit_pub))) - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_DONAU_GENERIC_KEYS_MISSING, - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "public key value: %lu.%u\n", - dk->value.value, dk->value.fraction); - GNUNET_assert (0 <= TALER_amount_add (&receipts_sum, - &receipts_sum, - &dk->value)); - } - struct TALER_Amount new_receipts_to_date; - - TALER_amount_add (&new_receipts_to_date, - &receipts_sum, - &charity_meta.receipts_to_date); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "new_receipts_to_date: %lu.%u, receipts_sum: %lu.%u, charity_max_per_year: %lu.%u\n", - new_receipts_to_date.value, new_receipts_to_date.fraction, - receipts_sum.value, - receipts_sum.fraction, charity_meta.max_per_year.value, - charity_meta.max_per_year.fraction); - // new_receipts_to_date has to be smaller or equal as max_per_year - if (0 < TALER_amount_cmp (&new_receipts_to_date, &charity_meta.max_per_year)) - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_EXCEEDING_DONATION_LIMIT, - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "calculated the new receipts to date amount\n"); - - /* sign budis and send the signatures back */ - struct DONAU_BlindedDonationUnitSignature du_sigs[num_bkps]; - struct BUDIKeyPair_sign_data bkps_sign_data[num_bkps]; - - for (int i = 0; i < num_bkps; i++) - { - bkps_sign_data[i].h_donation_unit_pub = &bkps[i].h_donation_unit_pub; - bkps_sign_data[i].budi = &bkps[i].blinded_udi; - } - if (TALER_EC_NONE != DH_keys_donation_unit_batch_sign (num_bkps, - bkps_sign_data, - du_sigs)) - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, // TODO:other EC - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "made blind signatures!\n"); - /* save new receipts to date and save receipts Request (blinded signatures, - * charity id, amount, hash over bkps) to make it idempotent*/ - enum GNUNET_DB_QueryStatus qs_insert_ir; - qs_insert_ir = DH_plugin->insert_issued_receipt ( - DH_plugin->cls, - num_bkps, - du_sigs, - (uint64_t) charity_id, - &h_receipts, - &receipts_sum, - &new_receipts_to_date); - switch (qs_insert_ir) - { - 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_assert (! second_time); - second_time = true; - goto start; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "issue receipts request is saved! (idempotent)\n"); - - signatures_to_JSON (num_bkps, du_sigs, blind_signatures); - return TALER_MHD_REPLY_JSON_PACK ( - rc->connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ("blind_signatures", - blind_signatures)); -} - - -/* end of donau-httpd_post-batch-issue.c */ diff --git a/src/donau/donau-httpd_post-submit-receipts.c b/src/donau/donau-httpd_post-submit-receipts.c @@ -1,155 +0,0 @@ -/* - 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 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 donau-httpd_post-submit-receipts.c - * @brief Handle request to insert a submitted receipt. - * @author Johannes Casaburi - */ -#include "taler/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/taler_json_lib.h" -#include "taler/taler_mhd_lib.h" -#include "taler/taler_signatures.h" -#include "donaudb_plugin.h" -#include "donau-httpd_submit-receipts.h" -#include "donau-httpd_db.h" -#include "donau-httpd_metrics.h" - - -/** - * Closure for #insert_submitted_receipt() - */ -struct InsertReceiptContext -{ - struct DONAU_HashDonorTaxId *h_tax_number; - union GNUNET_CRYPTO_BlindSessionNonce *nonce; - struct DONAU_DonationUnitPublicKey *donation_unit_pub; - struct DONAU_DonauSignatureP *donau_sig; - uint64_t donation_year; -}; - - -/** - * Function implementing insert submit-receipt transaction. - * - * Runs the transaction logic; IF it returns a non-error code, the - * transaction logic MUST NOT queue a MHD response. IF it returns an hard - * error, the transaction logic MUST queue a MHD response and set @a mhd_ret. - * IF it returns the soft error code, the function MAY be called again to - * retry and MUST not queue a MHD response. - * - * @param cls closure with a `struct InsertReceiptContext` - * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, - * if transaction failed (!) - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -insert_submitted_receipt (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct InsertReceiptContext *irc = cls; - enum GNUNET_DB_QueryStatus qs; - - qs = DH_plugin->insert_submitted_receipt (DH_plugin->cls, - irc->h_tax_number, - irc->nonce, - irc->donation_unit_pub, - irc->donau_sig, - irc->donation_year); - if (qs <= 0) - { - if (GNUNET_DB_STATUS_SOFT_ERROR != qs) - { - GNUNET_break (0); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - "insert_submitted_receipt"); - return GNUNET_DB_STATUS_HARD_ERROR; - } - return qs; - } - - return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -} - - -MHD_RESULT -DH_handler_submit_receipts_post (struct DH_RequestContext *rc, - const json_t *root, - const char *const args[]) -{ - struct InsertReceiptContext irc; - - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("h_tax_number", - &irc.h_tax_number), - GNUNET_JSON_spec_fixed_auto ("nonce", - &irc.nonce), - GNUNET_JSON_spec_fixed_auto ("donation_unit_pub", - &irc.donation_unit_pub), - GNUNET_JSON_spec_fixed_auto ("donau_sig", - &irc.donau_sig), - GNUNET_JSON_spec_uint64 ("donation_year", - &irc.donation_year), - GNUNET_JSON_spec_end () - }; - - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (rc->connection, - root, - spec); - if (GNUNET_SYSERR == res) - return MHD_NO; /* hard failure */ - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - return MHD_YES; /* failure */ - } - } - - { - MHD_RESULT mhd_ret; - - if (GNUNET_OK != - DH_DB_run_transaction (rc->connection, - "insert_submitted_receipt", - DH_MT_REQUEST_OTHER, - &mhd_ret, - &insert_submitted_receipt, - &irc)) - { - return mhd_ret; - } - } - return TALER_MHD_reply_static ( - rc->connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); -} - - -/* end of donau-httpd_post-submit-receipts.c */ diff --git a/src/donau/donau-httpd_submit-receipts.h b/src/donau/donau-httpd_submit-receipts.h @@ -1,41 +0,0 @@ -/* - 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 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 donau-httpd_submit-receipts.h - * @brief Handle /submit requests - * @author Johannes Casaburi - */ -#ifndef DONAU_HTTPD_SUBMIT_RECEIPT_H -#define DONAU_HTTPD_SUBMIT_RECEIPT_H - -#include <microhttpd.h> -#include "donau-httpd.h" - - -/** - * Handle a POST "/submit" request. - * - * @param connection the MHD connection to handle - * @param root uploaded JSON data - * @return MHD result code - */ -MHD_RESULT -DH_handler_submit_receipts_post ( - struct DH_RequestContext *rc, - const json_t *root, - const char *const args[]); - -#endif