LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_responses.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 259 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-httpd_responses.c
      18             :  * @brief API for generating generic replies of the exchange; these
      19             :  *        functions are called TEH_RESPONSE_reply_ and they generate
      20             :  *        and queue MHD response objects for a given connection.
      21             :  * @author Florian Dold
      22             :  * @author Benedikt Mueller
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "platform.h"
      26             : #include <zlib.h>
      27             : #include "taler-exchange-httpd_responses.h"
      28             : #include "taler_util.h"
      29             : #include "taler_json_lib.h"
      30             : #include "taler_mhd_lib.h"
      31             : #include "taler-exchange-httpd_keys.h"
      32             : 
      33             : 
      34             : /**
      35             :  * Compile the transaction history of a coin into a JSON object.
      36             :  *
      37             :  * @param coin_pub public key of the coin
      38             :  * @param tl transaction history to JSON-ify
      39             :  * @return json representation of the @a rh, NULL on error
      40             :  */
      41             : json_t *
      42           0 : TEH_RESPONSE_compile_transaction_history (
      43             :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
      44             :   const struct TALER_EXCHANGEDB_TransactionList *tl)
      45             : {
      46             :   json_t *history;
      47             : 
      48           0 :   history = json_array ();
      49           0 :   if (NULL == history)
      50             :   {
      51           0 :     GNUNET_break (0); /* out of memory!? */
      52           0 :     return NULL;
      53             :   }
      54           0 :   for (const struct TALER_EXCHANGEDB_TransactionList *pos = tl;
      55             :        NULL != pos;
      56           0 :        pos = pos->next)
      57             :   {
      58           0 :     switch (pos->type)
      59             :     {
      60           0 :     case TALER_EXCHANGEDB_TT_DEPOSIT:
      61             :       {
      62           0 :         const struct TALER_EXCHANGEDB_DepositListEntry *deposit =
      63             :           pos->details.deposit;
      64             :         struct TALER_MerchantWireHashP h_wire;
      65             : 
      66           0 :         TALER_merchant_wire_signature_hash (deposit->receiver_wire_account,
      67             :                                             &deposit->wire_salt,
      68             :                                             &h_wire);
      69             : #if ENABLE_SANITY_CHECKS
      70             :         /* internal sanity check before we hand out a bogus sig... */
      71           0 :         TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
      72           0 :         if (GNUNET_OK !=
      73           0 :             TALER_wallet_deposit_verify (
      74             :               &deposit->amount_with_fee,
      75             :               &deposit->deposit_fee,
      76             :               &h_wire,
      77             :               &deposit->h_contract_terms,
      78             :               &deposit->h_age_commitment,
      79             :               NULL /* h_extensions! */,
      80             :               &deposit->h_denom_pub,
      81             :               deposit->timestamp,
      82             :               &deposit->merchant_pub,
      83             :               deposit->refund_deadline,
      84             :               coin_pub,
      85             :               &deposit->csig))
      86             :         {
      87           0 :           GNUNET_break (0);
      88           0 :           json_decref (history);
      89           0 :           return NULL;
      90             :         }
      91             : #endif
      92           0 :         if (0 !=
      93           0 :             json_array_append_new (
      94             :               history,
      95           0 :               GNUNET_JSON_PACK (
      96             :                 GNUNET_JSON_pack_string ("type",
      97             :                                          "DEPOSIT"),
      98             :                 TALER_JSON_pack_amount ("amount",
      99             :                                         &deposit->amount_with_fee),
     100             :                 TALER_JSON_pack_amount ("deposit_fee",
     101             :                                         &deposit->deposit_fee),
     102             :                 GNUNET_JSON_pack_timestamp ("timestamp",
     103             :                                             deposit->timestamp),
     104             :                 GNUNET_JSON_pack_allow_null (
     105             :                   GNUNET_JSON_pack_timestamp ("refund_deadline",
     106             :                                               deposit->refund_deadline)),
     107             :                 GNUNET_JSON_pack_data_auto ("merchant_pub",
     108             :                                             &deposit->merchant_pub),
     109             :                 GNUNET_JSON_pack_data_auto ("h_contract_terms",
     110             :                                             &deposit->h_contract_terms),
     111             :                 GNUNET_JSON_pack_data_auto ("h_wire",
     112             :                                             &h_wire),
     113             :                 GNUNET_JSON_pack_allow_null (
     114             :                   deposit->no_age_commitment ?
     115             :                   GNUNET_JSON_pack_string (
     116             :                     "h_age_commitment", NULL) :
     117             :                   GNUNET_JSON_pack_data_auto ("h_age_commitment",
     118             :                                               &deposit->h_age_commitment)),
     119             :                 GNUNET_JSON_pack_data_auto ("coin_sig",
     120             :                                             &deposit->csig))))
     121             :         {
     122           0 :           GNUNET_break (0);
     123           0 :           json_decref (history);
     124           0 :           return NULL;
     125             :         }
     126           0 :         break;
     127             :       }
     128           0 :     case TALER_EXCHANGEDB_TT_MELT:
     129             :       {
     130           0 :         const struct TALER_EXCHANGEDB_MeltListEntry *melt =
     131             :           pos->details.melt;
     132           0 :         const struct TALER_AgeCommitmentHash *phac = NULL;
     133             : 
     134             : #if ENABLE_SANITY_CHECKS
     135           0 :         TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
     136           0 :         if (GNUNET_OK !=
     137           0 :             TALER_wallet_melt_verify (
     138             :               &melt->amount_with_fee,
     139             :               &melt->melt_fee,
     140             :               &melt->rc,
     141             :               &melt->h_denom_pub,
     142             :               &melt->h_age_commitment,
     143             :               coin_pub,
     144             :               &melt->coin_sig))
     145             :         {
     146           0 :           GNUNET_break (0);
     147           0 :           json_decref (history);
     148           0 :           return NULL;
     149             :         }
     150             : #endif
     151             : 
     152             :         /* Age restriction is optional.  We communicate a NULL value to
     153             :          * JSON_PACK below */
     154           0 :         if (! melt->no_age_commitment)
     155           0 :           phac = &melt->h_age_commitment;
     156             : 
     157           0 :         if (0 !=
     158           0 :             json_array_append_new (
     159             :               history,
     160           0 :               GNUNET_JSON_PACK (
     161             :                 GNUNET_JSON_pack_string ("type",
     162             :                                          "MELT"),
     163             :                 TALER_JSON_pack_amount ("amount",
     164             :                                         &melt->amount_with_fee),
     165             :                 TALER_JSON_pack_amount ("melt_fee",
     166             :                                         &melt->melt_fee),
     167             :                 GNUNET_JSON_pack_data_auto ("rc",
     168             :                                             &melt->rc),
     169             :                 GNUNET_JSON_pack_allow_null (
     170             :                   GNUNET_JSON_pack_data_auto ("h_age_commitment",
     171             :                                               phac)),
     172             :                 GNUNET_JSON_pack_data_auto ("coin_sig",
     173             :                                             &melt->coin_sig))))
     174             :         {
     175           0 :           GNUNET_break (0);
     176           0 :           json_decref (history);
     177           0 :           return NULL;
     178             :         }
     179             :       }
     180           0 :       break;
     181           0 :     case TALER_EXCHANGEDB_TT_REFUND:
     182             :       {
     183           0 :         const struct TALER_EXCHANGEDB_RefundListEntry *refund =
     184             :           pos->details.refund;
     185             :         struct TALER_Amount value;
     186             : 
     187             : #if ENABLE_SANITY_CHECKS
     188           0 :         TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
     189           0 :         if (GNUNET_OK !=
     190           0 :             TALER_merchant_refund_verify (
     191             :               coin_pub,
     192             :               &refund->h_contract_terms,
     193             :               refund->rtransaction_id,
     194             :               &refund->refund_amount,
     195             :               &refund->merchant_pub,
     196             :               &refund->merchant_sig))
     197             :         {
     198           0 :           GNUNET_break (0);
     199           0 :           json_decref (history);
     200           0 :           return NULL;
     201             :         }
     202             : #endif
     203           0 :         if (0 >
     204           0 :             TALER_amount_subtract (&value,
     205             :                                    &refund->refund_amount,
     206             :                                    &refund->refund_fee))
     207             :         {
     208           0 :           GNUNET_break (0);
     209           0 :           json_decref (history);
     210           0 :           return NULL;
     211             :         }
     212           0 :         if (0 !=
     213           0 :             json_array_append_new (
     214             :               history,
     215           0 :               GNUNET_JSON_PACK (
     216             :                 GNUNET_JSON_pack_string ("type",
     217             :                                          "REFUND"),
     218             :                 TALER_JSON_pack_amount ("amount",
     219             :                                         &value),
     220             :                 TALER_JSON_pack_amount ("refund_fee",
     221             :                                         &refund->refund_fee),
     222             :                 GNUNET_JSON_pack_data_auto ("h_contract_terms",
     223             :                                             &refund->h_contract_terms),
     224             :                 GNUNET_JSON_pack_data_auto ("merchant_pub",
     225             :                                             &refund->merchant_pub),
     226             :                 GNUNET_JSON_pack_uint64 ("rtransaction_id",
     227             :                                          refund->rtransaction_id),
     228             :                 GNUNET_JSON_pack_data_auto ("merchant_sig",
     229             :                                             &refund->merchant_sig))))
     230             :         {
     231           0 :           GNUNET_break (0);
     232           0 :           json_decref (history);
     233           0 :           return NULL;
     234             :         }
     235             :       }
     236           0 :       break;
     237           0 :     case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
     238             :       {
     239           0 :         struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
     240             :           pos->details.old_coin_recoup;
     241             :         struct TALER_ExchangePublicKeyP epub;
     242             :         struct TALER_ExchangeSignatureP esig;
     243             : 
     244           0 :         if (TALER_EC_NONE !=
     245           0 :             TALER_exchange_online_confirm_recoup_refresh_sign (
     246             :               &TEH_keys_exchange_sign_,
     247             :               pr->timestamp,
     248           0 :               &pr->value,
     249           0 :               &pr->coin.coin_pub,
     250           0 :               &pr->old_coin_pub,
     251             :               &epub,
     252             :               &esig))
     253             :         {
     254           0 :           GNUNET_break (0);
     255           0 :           json_decref (history);
     256           0 :           return NULL;
     257             :         }
     258             :         /* NOTE: we could also provide coin_pub's coin_sig, denomination key hash and
     259             :            the denomination key's RSA signature over coin_pub, but as the
     260             :            wallet should really already have this information (and cannot
     261             :            check or do anything with it anyway if it doesn't), it seems
     262             :            strictly unnecessary. */
     263           0 :         if (0 !=
     264           0 :             json_array_append_new (
     265             :               history,
     266           0 :               GNUNET_JSON_PACK (
     267             :                 GNUNET_JSON_pack_string ("type",
     268             :                                          "OLD-COIN-RECOUP"),
     269             :                 TALER_JSON_pack_amount ("amount",
     270             :                                         &pr->value),
     271             :                 GNUNET_JSON_pack_data_auto ("exchange_sig",
     272             :                                             &esig),
     273             :                 GNUNET_JSON_pack_data_auto ("exchange_pub",
     274             :                                             &epub),
     275             :                 GNUNET_JSON_pack_data_auto ("coin_pub",
     276             :                                             &pr->coin.coin_pub),
     277             :                 GNUNET_JSON_pack_timestamp ("timestamp",
     278             :                                             pr->timestamp))))
     279             :         {
     280           0 :           GNUNET_break (0);
     281           0 :           json_decref (history);
     282           0 :           return NULL;
     283             :         }
     284           0 :         break;
     285             :       }
     286           0 :     case TALER_EXCHANGEDB_TT_RECOUP:
     287             :       {
     288           0 :         const struct TALER_EXCHANGEDB_RecoupListEntry *recoup =
     289             :           pos->details.recoup;
     290             :         struct TALER_ExchangePublicKeyP epub;
     291             :         struct TALER_ExchangeSignatureP esig;
     292             : 
     293           0 :         if (TALER_EC_NONE !=
     294           0 :             TALER_exchange_online_confirm_recoup_sign (
     295             :               &TEH_keys_exchange_sign_,
     296             :               recoup->timestamp,
     297             :               &recoup->value,
     298             :               coin_pub,
     299             :               &recoup->reserve_pub,
     300             :               &epub,
     301             :               &esig))
     302             :         {
     303           0 :           GNUNET_break (0);
     304           0 :           json_decref (history);
     305           0 :           return NULL;
     306             :         }
     307           0 :         if (0 !=
     308           0 :             json_array_append_new (
     309             :               history,
     310           0 :               GNUNET_JSON_PACK (
     311             :                 GNUNET_JSON_pack_string ("type",
     312             :                                          "RECOUP"),
     313             :                 TALER_JSON_pack_amount ("amount",
     314             :                                         &recoup->value),
     315             :                 GNUNET_JSON_pack_data_auto ("exchange_sig",
     316             :                                             &esig),
     317             :                 GNUNET_JSON_pack_data_auto ("exchange_pub",
     318             :                                             &epub),
     319             :                 GNUNET_JSON_pack_data_auto ("reserve_pub",
     320             :                                             &recoup->reserve_pub),
     321             :                 GNUNET_JSON_pack_data_auto ("coin_sig",
     322             :                                             &recoup->coin_sig),
     323             :                 GNUNET_JSON_pack_data_auto ("coin_blind",
     324             :                                             &recoup->coin_blind),
     325             :                 GNUNET_JSON_pack_data_auto ("reserve_pub",
     326             :                                             &recoup->reserve_pub),
     327             :                 GNUNET_JSON_pack_timestamp ("timestamp",
     328             :                                             recoup->timestamp))))
     329             :         {
     330           0 :           GNUNET_break (0);
     331           0 :           json_decref (history);
     332           0 :           return NULL;
     333             :         }
     334             :       }
     335           0 :       break;
     336           0 :     case TALER_EXCHANGEDB_TT_RECOUP_REFRESH:
     337             :       {
     338           0 :         struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
     339             :           pos->details.recoup_refresh;
     340             :         struct TALER_ExchangePublicKeyP epub;
     341             :         struct TALER_ExchangeSignatureP esig;
     342             : 
     343           0 :         if (TALER_EC_NONE !=
     344           0 :             TALER_exchange_online_confirm_recoup_refresh_sign (
     345             :               &TEH_keys_exchange_sign_,
     346             :               pr->timestamp,
     347           0 :               &pr->value,
     348             :               coin_pub,
     349           0 :               &pr->old_coin_pub,
     350             :               &epub,
     351             :               &esig))
     352             :         {
     353           0 :           GNUNET_break (0);
     354           0 :           json_decref (history);
     355           0 :           return NULL;
     356             :         }
     357             :         /* NOTE: we could also provide coin_pub's coin_sig, denomination key
     358             :            hash and the denomination key's RSA signature over coin_pub, but as
     359             :            the wallet should really already have this information (and cannot
     360             :            check or do anything with it anyway if it doesn't), it seems
     361             :            strictly unnecessary. */
     362           0 :         if (0 !=
     363           0 :             json_array_append_new (
     364             :               history,
     365           0 :               GNUNET_JSON_PACK (
     366             :                 GNUNET_JSON_pack_string ("type",
     367             :                                          "RECOUP-REFRESH"),
     368             :                 TALER_JSON_pack_amount ("amount",
     369             :                                         &pr->value),
     370             :                 GNUNET_JSON_pack_data_auto ("exchange_sig",
     371             :                                             &esig),
     372             :                 GNUNET_JSON_pack_data_auto ("exchange_pub",
     373             :                                             &epub),
     374             :                 GNUNET_JSON_pack_data_auto ("old_coin_pub",
     375             :                                             &pr->old_coin_pub),
     376             :                 GNUNET_JSON_pack_data_auto ("coin_sig",
     377             :                                             &pr->coin_sig),
     378             :                 GNUNET_JSON_pack_data_auto ("coin_blind",
     379             :                                             &pr->coin_blind),
     380             :                 GNUNET_JSON_pack_timestamp ("timestamp",
     381             :                                             pr->timestamp))))
     382             :         {
     383           0 :           GNUNET_break (0);
     384           0 :           json_decref (history);
     385           0 :           return NULL;
     386             :         }
     387           0 :         break;
     388             :       }
     389             : 
     390           0 :     case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT:
     391             :       {
     392           0 :         struct TALER_EXCHANGEDB_PurseDepositListEntry *pd
     393             :           = pos->details.purse_deposit;
     394           0 :         const struct TALER_AgeCommitmentHash *phac = NULL;
     395             : 
     396           0 :         if (! pd->no_age_commitment)
     397           0 :           phac = &pd->h_age_commitment;
     398             : 
     399           0 :         if (0 !=
     400           0 :             json_array_append_new (
     401             :               history,
     402           0 :               GNUNET_JSON_PACK (
     403             :                 GNUNET_JSON_pack_string ("type",
     404             :                                          "PURSE-DEPOSIT"),
     405             :                 TALER_JSON_pack_amount ("amount",
     406             :                                         &pd->amount),
     407             :                 GNUNET_JSON_pack_string ("exchange_base_url",
     408             :                                          NULL == pd->exchange_base_url
     409             :                                          ? TEH_base_url
     410             :                                          : pd->exchange_base_url),
     411             :                 GNUNET_JSON_pack_allow_null (
     412             :                   GNUNET_JSON_pack_data_auto ("h_age_commitment",
     413             :                                               phac)),
     414             :                 GNUNET_JSON_pack_data_auto ("purse_pub",
     415             :                                             &pd->purse_pub),
     416             :                 GNUNET_JSON_pack_bool ("refunded",
     417             :                                        pd->refunded),
     418             :                 GNUNET_JSON_pack_data_auto ("coin_sig",
     419             :                                             &pd->coin_sig))))
     420             :         {
     421           0 :           GNUNET_break (0);
     422           0 :           json_decref (history);
     423           0 :           return NULL;
     424             :         }
     425           0 :         break;
     426             :       }
     427             :     }
     428           0 :   }
     429           0 :   return history;
     430             : }
     431             : 
     432             : 
     433             : MHD_RESULT
     434           0 : TEH_RESPONSE_reply_unknown_denom_pub_hash (
     435             :   struct MHD_Connection *connection,
     436             :   const struct TALER_DenominationHashP *dph)
     437             : {
     438             :   struct TALER_ExchangePublicKeyP epub;
     439             :   struct TALER_ExchangeSignatureP esig;
     440             :   struct GNUNET_TIME_Timestamp now;
     441             :   enum TALER_ErrorCode ec;
     442             : 
     443           0 :   now = GNUNET_TIME_timestamp_get ();
     444           0 :   ec = TALER_exchange_online_denomination_unknown_sign (
     445             :     &TEH_keys_exchange_sign_,
     446             :     now,
     447             :     dph,
     448             :     &epub,
     449             :     &esig);
     450           0 :   if (TALER_EC_NONE != ec)
     451             :   {
     452           0 :     GNUNET_break (0);
     453           0 :     return TALER_MHD_reply_with_error (connection,
     454             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     455             :                                        ec,
     456             :                                        NULL);
     457             :   }
     458           0 :   return TALER_MHD_REPLY_JSON_PACK (
     459             :     connection,
     460             :     MHD_HTTP_NOT_FOUND,
     461             :     TALER_JSON_pack_ec (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN),
     462             :     GNUNET_JSON_pack_timestamp ("timestamp",
     463             :                                 now),
     464             :     GNUNET_JSON_pack_data_auto ("exchange_pub",
     465             :                                 &epub),
     466             :     GNUNET_JSON_pack_data_auto ("exchange_sig",
     467             :                                 &esig),
     468             :     GNUNET_JSON_pack_data_auto ("h_denom_pub",
     469             :                                 dph));
     470             : }
     471             : 
     472             : 
     473             : MHD_RESULT
     474           0 : TEH_RESPONSE_reply_expired_denom_pub_hash (
     475             :   struct MHD_Connection *connection,
     476             :   const struct TALER_DenominationHashP *dph,
     477             :   enum TALER_ErrorCode ec,
     478             :   const char *oper)
     479             : {
     480             :   struct TALER_ExchangePublicKeyP epub;
     481             :   struct TALER_ExchangeSignatureP esig;
     482             :   enum TALER_ErrorCode ecr;
     483             :   struct GNUNET_TIME_Timestamp now
     484           0 :     = GNUNET_TIME_timestamp_get ();
     485             : 
     486           0 :   ecr = TALER_exchange_online_denomination_expired_sign (
     487             :     &TEH_keys_exchange_sign_,
     488             :     now,
     489             :     dph,
     490             :     oper,
     491             :     &epub,
     492             :     &esig);
     493           0 :   if (TALER_EC_NONE != ecr)
     494             :   {
     495           0 :     GNUNET_break (0);
     496           0 :     return TALER_MHD_reply_with_error (connection,
     497             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     498             :                                        ec,
     499             :                                        NULL);
     500             :   }
     501           0 :   return TALER_MHD_REPLY_JSON_PACK (
     502             :     connection,
     503             :     MHD_HTTP_GONE,
     504             :     TALER_JSON_pack_ec (ec),
     505             :     GNUNET_JSON_pack_string ("oper",
     506             :                              oper),
     507             :     GNUNET_JSON_pack_timestamp ("timestamp",
     508             :                                 now),
     509             :     GNUNET_JSON_pack_data_auto ("exchange_pub",
     510             :                                 &epub),
     511             :     GNUNET_JSON_pack_data_auto ("exchange_sig",
     512             :                                 &esig),
     513             :     GNUNET_JSON_pack_data_auto ("h_denom_pub",
     514             :                                 dph));
     515             : }
     516             : 
     517             : 
     518             : MHD_RESULT
     519           0 : TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
     520             :   struct MHD_Connection *connection,
     521             :   const struct TALER_DenominationHashP *dph)
     522             : {
     523             :   struct TALER_ExchangePublicKeyP epub;
     524             :   struct TALER_ExchangeSignatureP esig;
     525             :   struct GNUNET_TIME_Timestamp now;
     526             :   enum TALER_ErrorCode ec;
     527             : 
     528           0 :   now = GNUNET_TIME_timestamp_get ();
     529           0 :   ec = TALER_exchange_online_denomination_unknown_sign (
     530             :     &TEH_keys_exchange_sign_,
     531             :     now,
     532             :     dph,
     533             :     &epub,
     534             :     &esig);
     535           0 :   if (TALER_EC_NONE != ec)
     536             :   {
     537           0 :     GNUNET_break (0);
     538           0 :     return TALER_MHD_reply_with_error (connection,
     539             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     540             :                                        ec,
     541             :                                        NULL);
     542             :   }
     543           0 :   return TALER_MHD_REPLY_JSON_PACK (
     544             :     connection,
     545             :     MHD_HTTP_NOT_FOUND,
     546             :     TALER_JSON_pack_ec (
     547             :       TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION),
     548             :     GNUNET_JSON_pack_timestamp ("timestamp",
     549             :                                 now),
     550             :     GNUNET_JSON_pack_data_auto ("exchange_pub",
     551             :                                 &epub),
     552             :     GNUNET_JSON_pack_data_auto ("exchange_sig",
     553             :                                 &esig),
     554             :     GNUNET_JSON_pack_data_auto ("h_denom_pub",
     555             :                                 dph));
     556             : }
     557             : 
     558             : 
     559             : MHD_RESULT
     560           0 : TEH_RESPONSE_reply_coin_insufficient_funds (
     561             :   struct MHD_Connection *connection,
     562             :   enum TALER_ErrorCode ec,
     563             :   const struct TALER_DenominationHashP *h_denom_pub,
     564             :   const struct TALER_CoinSpendPublicKeyP *coin_pub)
     565             : {
     566             :   struct TALER_EXCHANGEDB_TransactionList *tl;
     567             :   enum GNUNET_DB_QueryStatus qs;
     568             :   json_t *history;
     569             : 
     570           0 :   TEH_plugin->rollback (TEH_plugin->cls);
     571           0 :   if (GNUNET_OK !=
     572           0 :       TEH_plugin->start_read_only (TEH_plugin->cls,
     573             :                                    "get_coin_transactions"))
     574             :   {
     575           0 :     return TALER_MHD_reply_with_error (
     576             :       connection,
     577             :       MHD_HTTP_INTERNAL_SERVER_ERROR,
     578             :       TALER_EC_GENERIC_DB_START_FAILED,
     579             :       NULL);
     580             :   }
     581           0 :   qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
     582             :                                           coin_pub,
     583             :                                           &tl);
     584           0 :   TEH_plugin->rollback (TEH_plugin->cls);
     585           0 :   if (0 > qs)
     586             :   {
     587           0 :     return TALER_MHD_reply_with_error (
     588             :       connection,
     589             :       MHD_HTTP_INTERNAL_SERVER_ERROR,
     590             :       TALER_EC_GENERIC_DB_FETCH_FAILED,
     591             :       NULL);
     592             :   }
     593             : 
     594           0 :   history = TEH_RESPONSE_compile_transaction_history (coin_pub,
     595             :                                                       tl);
     596           0 :   TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
     597             :                                           tl);
     598           0 :   if (NULL == history)
     599             :   {
     600           0 :     GNUNET_break (0);
     601           0 :     return TALER_MHD_reply_with_error (connection,
     602             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     603             :                                        TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
     604             :                                        "Failed to generated proof of insufficient funds");
     605             :   }
     606           0 :   return TALER_MHD_REPLY_JSON_PACK (
     607             :     connection,
     608             :     TALER_ErrorCode_get_http_status_safe (ec),
     609             :     TALER_JSON_pack_ec (ec),
     610             :     GNUNET_JSON_pack_data_auto ("coin_pub",
     611             :                                 coin_pub),
     612             :     GNUNET_JSON_pack_data_auto ("h_denom_pub",
     613             :                                 h_denom_pub),
     614             :     GNUNET_JSON_pack_array_steal ("history",
     615             :                                   history));
     616             : }
     617             : 
     618             : 
     619             : json_t *
     620           0 : TEH_RESPONSE_compile_reserve_history (
     621             :   const struct TALER_EXCHANGEDB_ReserveHistory *rh)
     622             : {
     623             :   json_t *json_history;
     624             : 
     625           0 :   json_history = json_array ();
     626           0 :   for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh;
     627             :        NULL != pos;
     628           0 :        pos = pos->next)
     629             :   {
     630           0 :     switch (pos->type)
     631             :     {
     632           0 :     case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
     633             :       {
     634           0 :         const struct TALER_EXCHANGEDB_BankTransfer *bank =
     635             :           pos->details.bank;
     636             : 
     637           0 :         if (0 !=
     638           0 :             json_array_append_new (
     639             :               json_history,
     640           0 :               GNUNET_JSON_PACK (
     641             :                 GNUNET_JSON_pack_string ("type",
     642             :                                          "CREDIT"),
     643             :                 GNUNET_JSON_pack_timestamp ("timestamp",
     644             :                                             bank->execution_date),
     645             :                 GNUNET_JSON_pack_string ("sender_account_url",
     646             :                                          bank->sender_account_details),
     647             :                 GNUNET_JSON_pack_uint64 ("wire_reference",
     648             :                                          bank->wire_reference),
     649             :                 TALER_JSON_pack_amount ("amount",
     650             :                                         &bank->amount))))
     651             :         {
     652           0 :           GNUNET_break (0);
     653           0 :           json_decref (json_history);
     654           0 :           return NULL;
     655             :         }
     656           0 :         break;
     657             :       }
     658           0 :     case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
     659             :       {
     660           0 :         const struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw
     661             :           = pos->details.withdraw;
     662             : 
     663           0 :         if (0 !=
     664           0 :             json_array_append_new (
     665             :               json_history,
     666           0 :               GNUNET_JSON_PACK (
     667             :                 GNUNET_JSON_pack_string ("type",
     668             :                                          "WITHDRAW"),
     669             :                 GNUNET_JSON_pack_data_auto ("reserve_sig",
     670             :                                             &withdraw->reserve_sig),
     671             :                 GNUNET_JSON_pack_data_auto ("h_coin_envelope",
     672             :                                             &withdraw->h_coin_envelope),
     673             :                 GNUNET_JSON_pack_data_auto ("h_denom_pub",
     674             :                                             &withdraw->denom_pub_hash),
     675             :                 TALER_JSON_pack_amount ("withdraw_fee",
     676             :                                         &withdraw->withdraw_fee),
     677             :                 TALER_JSON_pack_amount ("amount",
     678             :                                         &withdraw->amount_with_fee))))
     679             :         {
     680           0 :           GNUNET_break (0);
     681           0 :           json_decref (json_history);
     682           0 :           return NULL;
     683             :         }
     684             :       }
     685           0 :       break;
     686           0 :     case TALER_EXCHANGEDB_RO_RECOUP_COIN:
     687             :       {
     688           0 :         const struct TALER_EXCHANGEDB_Recoup *recoup
     689             :           = pos->details.recoup;
     690             :         struct TALER_ExchangePublicKeyP pub;
     691             :         struct TALER_ExchangeSignatureP sig;
     692             : 
     693           0 :         if (TALER_EC_NONE !=
     694           0 :             TALER_exchange_online_confirm_recoup_sign (
     695             :               &TEH_keys_exchange_sign_,
     696             :               recoup->timestamp,
     697             :               &recoup->value,
     698             :               &recoup->coin.coin_pub,
     699             :               &recoup->reserve_pub,
     700             :               &pub,
     701             :               &sig))
     702             :         {
     703           0 :           GNUNET_break (0);
     704           0 :           json_decref (json_history);
     705           0 :           return NULL;
     706             :         }
     707             : 
     708           0 :         if (0 !=
     709           0 :             json_array_append_new (
     710             :               json_history,
     711           0 :               GNUNET_JSON_PACK (
     712             :                 GNUNET_JSON_pack_string ("type",
     713             :                                          "RECOUP"),
     714             :                 GNUNET_JSON_pack_data_auto ("exchange_pub",
     715             :                                             &pub),
     716             :                 GNUNET_JSON_pack_data_auto ("exchange_sig",
     717             :                                             &sig),
     718             :                 GNUNET_JSON_pack_timestamp ("timestamp",
     719             :                                             recoup->timestamp),
     720             :                 TALER_JSON_pack_amount ("amount",
     721             :                                         &recoup->value),
     722             :                 GNUNET_JSON_pack_data_auto ("coin_pub",
     723             :                                             &recoup->coin.coin_pub))))
     724             :         {
     725           0 :           GNUNET_break (0);
     726           0 :           json_decref (json_history);
     727           0 :           return NULL;
     728             :         }
     729             :       }
     730           0 :       break;
     731           0 :     case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
     732             :       {
     733           0 :         const struct TALER_EXCHANGEDB_ClosingTransfer *closing =
     734             :           pos->details.closing;
     735             :         struct TALER_ExchangePublicKeyP pub;
     736             :         struct TALER_ExchangeSignatureP sig;
     737             : 
     738           0 :         if (TALER_EC_NONE !=
     739           0 :             TALER_exchange_online_reserve_closed_sign (
     740             :               &TEH_keys_exchange_sign_,
     741             :               closing->execution_date,
     742             :               &closing->amount,
     743             :               &closing->closing_fee,
     744           0 :               closing->receiver_account_details,
     745             :               &closing->wtid,
     746           0 :               &pos->details.closing->reserve_pub,
     747             :               &pub,
     748             :               &sig))
     749             :         {
     750           0 :           GNUNET_break (0);
     751           0 :           json_decref (json_history);
     752           0 :           return NULL;
     753             :         }
     754           0 :         if (0 !=
     755           0 :             json_array_append_new (
     756             :               json_history,
     757           0 :               GNUNET_JSON_PACK (
     758             :                 GNUNET_JSON_pack_string ("type",
     759             :                                          "CLOSING"),
     760             :                 GNUNET_JSON_pack_string ("receiver_account_details",
     761             :                                          closing->receiver_account_details),
     762             :                 GNUNET_JSON_pack_data_auto ("wtid",
     763             :                                             &closing->wtid),
     764             :                 GNUNET_JSON_pack_data_auto ("exchange_pub",
     765             :                                             &pub),
     766             :                 GNUNET_JSON_pack_data_auto ("exchange_sig",
     767             :                                             &sig),
     768             :                 GNUNET_JSON_pack_timestamp ("timestamp",
     769             :                                             closing->execution_date),
     770             :                 TALER_JSON_pack_amount ("amount",
     771             :                                         &closing->amount),
     772             :                 TALER_JSON_pack_amount ("closing_fee",
     773             :                                         &closing->closing_fee))))
     774             :         {
     775           0 :           GNUNET_break (0);
     776           0 :           json_decref (json_history);
     777           0 :           return NULL;
     778             :         }
     779             :       }
     780           0 :       break;
     781           0 :     case TALER_EXCHANGEDB_RO_PURSE_MERGE:
     782             :       {
     783           0 :         const struct TALER_EXCHANGEDB_PurseMerge *merge =
     784             :           pos->details.merge;
     785             : 
     786           0 :         if (0 !=
     787           0 :             json_array_append_new (
     788             :               json_history,
     789           0 :               GNUNET_JSON_PACK (
     790             :                 GNUNET_JSON_pack_string ("type",
     791             :                                          "MERGE"),
     792             :                 GNUNET_JSON_pack_data_auto ("h_contract_terms",
     793             :                                             &merge->h_contract_terms),
     794             :                 GNUNET_JSON_pack_data_auto ("merge_pub",
     795             :                                             &merge->merge_pub),
     796             :                 GNUNET_JSON_pack_uint64 ("min_age",
     797             :                                          merge->min_age),
     798             :                 GNUNET_JSON_pack_uint64 ("flags",
     799             :                                          merge->flags),
     800             :                 GNUNET_JSON_pack_data_auto ("purse_pub",
     801             :                                             &merge->purse_pub),
     802             :                 GNUNET_JSON_pack_data_auto ("reserve_sig",
     803             :                                             &merge->reserve_sig),
     804             :                 GNUNET_JSON_pack_timestamp ("merge_timestamp",
     805             :                                             merge->merge_timestamp),
     806             :                 GNUNET_JSON_pack_timestamp ("purse_expiration",
     807             :                                             merge->purse_expiration),
     808             :                 TALER_JSON_pack_amount ("amount",
     809             :                                         &merge->amount_with_fee),
     810             :                 TALER_JSON_pack_amount ("purse_fee",
     811             :                                         &merge->purse_fee),
     812             :                 GNUNET_JSON_pack_bool ("merged",
     813             :                                        merge->merged))))
     814             :         {
     815           0 :           GNUNET_break (0);
     816           0 :           json_decref (json_history);
     817           0 :           return NULL;
     818             :         }
     819             :       }
     820           0 :       break;
     821           0 :     case TALER_EXCHANGEDB_RO_HISTORY_REQUEST:
     822             :       {
     823           0 :         const struct TALER_EXCHANGEDB_HistoryRequest *history =
     824             :           pos->details.history;
     825             : 
     826           0 :         if (0 !=
     827           0 :             json_array_append_new (
     828             :               json_history,
     829           0 :               GNUNET_JSON_PACK (
     830             :                 GNUNET_JSON_pack_string ("type",
     831             :                                          "HISTORY"),
     832             :                 GNUNET_JSON_pack_data_auto ("reserve_sig",
     833             :                                             &history->reserve_sig),
     834             :                 GNUNET_JSON_pack_timestamp ("request_timestamp",
     835             :                                             history->request_timestamp),
     836             :                 TALER_JSON_pack_amount ("amount",
     837             :                                         &history->history_fee))))
     838             :         {
     839           0 :           GNUNET_break (0);
     840           0 :           json_decref (json_history);
     841           0 :           return NULL;
     842             :         }
     843             :       }
     844           0 :       break;
     845             :     }
     846           0 :   }
     847             : 
     848           0 :   return json_history;
     849             : }
     850             : 
     851             : 
     852             : /**
     853             :  * Send reserve history information to client with the
     854             :  * message that we have insufficient funds for the
     855             :  * requested withdraw operation.
     856             :  *
     857             :  * @param connection connection to the client
     858             :  * @param ebalance expected balance based on our database
     859             :  * @param withdraw_amount amount that the client requested to withdraw
     860             :  * @param rh reserve history to return
     861             :  * @return MHD result code
     862             :  */
     863             : static MHD_RESULT
     864           0 : reply_withdraw_insufficient_funds (
     865             :   struct MHD_Connection *connection,
     866             :   const struct TALER_Amount *ebalance,
     867             :   const struct TALER_Amount *withdraw_amount,
     868             :   const struct TALER_EXCHANGEDB_ReserveHistory *rh)
     869             : {
     870             :   json_t *json_history;
     871             : 
     872           0 :   json_history = TEH_RESPONSE_compile_reserve_history (rh);
     873           0 :   if (NULL == json_history)
     874           0 :     return TALER_MHD_reply_with_error (connection,
     875             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     876             :                                        TALER_EC_EXCHANGE_WITHDRAW_HISTORY_ERROR_INSUFFICIENT_FUNDS,
     877             :                                        NULL);
     878           0 :   return TALER_MHD_REPLY_JSON_PACK (
     879             :     connection,
     880             :     MHD_HTTP_CONFLICT,
     881             :     TALER_JSON_pack_ec (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS),
     882             :     TALER_JSON_pack_amount ("balance",
     883             :                             ebalance),
     884             :     TALER_JSON_pack_amount ("requested_amount",
     885             :                             withdraw_amount),
     886             :     GNUNET_JSON_pack_array_steal ("history",
     887             :                                   json_history));
     888             : }
     889             : 
     890             : 
     891             : MHD_RESULT
     892           0 : TEH_RESPONSE_reply_reserve_insufficient_balance (
     893             :   struct MHD_Connection *connection,
     894             :   const struct TALER_Amount *balance_required,
     895             :   const struct TALER_ReservePublicKeyP *reserve_pub)
     896             : {
     897           0 :   struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL;
     898             :   struct TALER_Amount balance;
     899             :   enum GNUNET_DB_QueryStatus qs;
     900             :   MHD_RESULT mhd_ret;
     901             : 
     902           0 :   if (GNUNET_OK !=
     903           0 :       TEH_plugin->start_read_only (TEH_plugin->cls,
     904             :                                    "get_reserve_history on insufficient balance"))
     905             :   {
     906           0 :     GNUNET_break (0);
     907           0 :     return TALER_MHD_reply_with_error (connection,
     908             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     909             :                                        TALER_EC_GENERIC_DB_START_FAILED,
     910             :                                        NULL);
     911             :   }
     912             :   /* The reserve does not have the required amount (actual
     913             :    * amount + withdraw fee) */
     914           0 :   qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
     915             :                                         reserve_pub,
     916             :                                         &balance,
     917             :                                         &rh);
     918           0 :   TEH_plugin->rollback (TEH_plugin->cls);
     919           0 :   if ( (qs < 0) ||
     920           0 :        (NULL == rh) )
     921             :   {
     922           0 :     return TALER_MHD_reply_with_error (connection,
     923             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     924             :                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
     925             :                                        "reserve history");
     926             :   }
     927           0 :   mhd_ret = reply_withdraw_insufficient_funds (
     928             :     connection,
     929             :     &balance,
     930             :     balance_required,
     931             :     rh);
     932           0 :   TEH_plugin->free_reserve_history (TEH_plugin->cls,
     933             :                                     rh);
     934           0 :   return mhd_ret;
     935             : }
     936             : 
     937             : 
     938             : MHD_RESULT
     939           0 : TEH_RESPONSE_reply_purse_created (
     940             :   struct MHD_Connection *connection,
     941             :   struct GNUNET_TIME_Timestamp exchange_timestamp,
     942             :   const struct TALER_Amount *purse_balance,
     943             :   const struct TEH_PurseDetails *pd)
     944             : {
     945             :   struct TALER_ExchangePublicKeyP pub;
     946             :   struct TALER_ExchangeSignatureP sig;
     947             :   enum TALER_ErrorCode ec;
     948             : 
     949           0 :   if (TALER_EC_NONE !=
     950           0 :       (ec = TALER_exchange_online_purse_created_sign (
     951             :          &TEH_keys_exchange_sign_,
     952             :          exchange_timestamp,
     953             :          pd->purse_expiration,
     954             :          &pd->target_amount,
     955             :          purse_balance,
     956             :          &pd->purse_pub,
     957             :          &pd->h_contract_terms,
     958             :          &pub,
     959             :          &sig)))
     960             :   {
     961           0 :     GNUNET_break (0);
     962           0 :     return TALER_MHD_reply_with_ec (connection,
     963             :                                     ec,
     964             :                                     NULL);
     965             :   }
     966           0 :   return TALER_MHD_REPLY_JSON_PACK (
     967             :     connection,
     968             :     MHD_HTTP_OK,
     969             :     TALER_JSON_pack_amount ("total_deposited",
     970             :                             purse_balance),
     971             :     GNUNET_JSON_pack_timestamp ("exchange_timestamp",
     972             :                                 exchange_timestamp),
     973             :     GNUNET_JSON_pack_data_auto ("exchange_sig",
     974             :                                 &sig),
     975             :     GNUNET_JSON_pack_data_auto ("exchange_pub",
     976             :                                 &pub));
     977             : }
     978             : 
     979             : 
     980             : MHD_RESULT
     981           0 : TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
     982             :                                  const struct TALER_PaytoHashP *h_payto,
     983             :                                  const struct TALER_EXCHANGEDB_KycStatus *kyc)
     984             : {
     985           0 :   return TALER_MHD_REPLY_JSON_PACK (
     986             :     connection,
     987             :     MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
     988             :     GNUNET_JSON_pack_data_auto ("h_payto",
     989             :                                 h_payto),
     990             :     GNUNET_JSON_pack_uint64 ("requirement_row",
     991             :                              kyc->requirement_row));
     992             : }
     993             : 
     994             : 
     995             : /* end of taler-exchange-httpd_responses.c */

Generated by: LCOV version 1.14