implementing #3632: generate proof of insufficient funds by converting transaction history to JSON
This commit is contained in:
parent
7b0ae9c1d0
commit
579f465c9b
@ -60,8 +60,20 @@ TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp);
|
||||
* @return the JSON reporesentation of the signature with purpose
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
const struct GNUNET_CRYPTO_EddsaSignature *signature);
|
||||
TALER_JSON_from_eddsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
const struct GNUNET_CRYPTO_EddsaSignature *signature);
|
||||
|
||||
|
||||
/**
|
||||
* Convert a signature (with purpose) to a JSON object representation.
|
||||
*
|
||||
* @param purpose purpose of the signature
|
||||
* @param signature the signature
|
||||
* @return the JSON reporesentation of the signature with purpose
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_ecdsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
const struct GNUNET_CRYPTO_EcdsaSignature *signature);
|
||||
|
||||
|
||||
/**
|
||||
@ -76,6 +88,17 @@ json_t *
|
||||
TALER_JSON_from_data (const void *data, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Convert binary hash to a JSON string with the base32crockford
|
||||
* encoding.
|
||||
*
|
||||
* @param hc binary data
|
||||
* @return json string that encodes @a hc
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_hash (const struct GNUNET_HashCode *hc);
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object to Amount
|
||||
*
|
||||
@ -119,7 +142,8 @@ TALER_JSON_to_data (json_t *json,
|
||||
* @return 1 if correctly formatted; 0 if not
|
||||
*/
|
||||
int
|
||||
TALER_JSON_validate_wireformat (const char *type, json_t *wire);
|
||||
TALER_JSON_validate_wireformat (const char *type,
|
||||
json_t *wire);
|
||||
|
||||
|
||||
#endif /* TALER_JSON_LIB_H_ */
|
||||
|
@ -266,7 +266,83 @@ struct RefreshMeltResponseSignatureBody
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Message signed by a coin to indicate that the coin should
|
||||
* be melted.
|
||||
*/
|
||||
struct RefreshMeltSignatureBody
|
||||
{
|
||||
/**
|
||||
* Purpose is #TALER_SIGNATURE_REFRESH_MELT.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* Which melting operation should the coin become a part of.
|
||||
*/
|
||||
struct GNUNET_HashCode melt_hash;
|
||||
|
||||
/**
|
||||
* How much of the value of the coin should be melted?
|
||||
* This amount includes the fees, so the final amount contributed
|
||||
* to the melt is this value minus the fee for melting the coin.
|
||||
*/
|
||||
struct TALER_AmountNBO amount;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Message signed during melting committing the client to the
|
||||
* hashed inputs.
|
||||
*/
|
||||
struct RefreshCommitSignatureBody
|
||||
{
|
||||
/**
|
||||
* Purpose is #TALER_SIGNATURE_REFRESH_COMMIT.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* Session state the client commits itself to.
|
||||
*/
|
||||
struct GNUNET_HashCode commit_hash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Message signed by the mint, committing it to a particular
|
||||
* index to not be revealed during the refresh.
|
||||
*/
|
||||
struct RefreshCommitResponseSignatureBody
|
||||
{
|
||||
/**
|
||||
* Purpose is #TALER_SIGNATURE_REFRESH_MELT_RESPONSE.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* Index that the client will not have to reveal.
|
||||
*/
|
||||
uint16_t noreveal_index GNUNET_PACKED;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Message signed by the client requesting the final
|
||||
* result of the melting operation.
|
||||
*/
|
||||
struct RefreshMeltConfirmSignRequestBody
|
||||
{
|
||||
/**
|
||||
* Purpose is #TALER_SIGNATURE_REFRESH_MELT_CONFIRM.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* FIXME.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@ -303,45 +379,6 @@ struct TALER_MINT_DenomKeyIssue
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct RefreshMeltSignatureBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_HashCode melt_hash;
|
||||
};
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct RefreshCommitSignatureBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_HashCode commit_hash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct RefreshCommitResponseSignatureBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
uint16_t noreveal_index;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct RefreshMeltConfirmSignRequestBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
|
||||
};
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
@ -222,8 +222,6 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
|
||||
const struct TALER_Amount balance,
|
||||
const struct GNUNET_TIME_Absolute expiry);
|
||||
|
||||
/* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */
|
||||
|
||||
|
||||
/**
|
||||
* Locate the response for a /withdraw request under the
|
||||
@ -529,10 +527,8 @@ TALER_MINT_DB_update_refresh_session (PGconn *db_conn,
|
||||
|
||||
/**
|
||||
* Specification for coin in a /refresh/melt operation.
|
||||
* FIXME: same as `struct MeltDetails`, and not by accident!
|
||||
* We should merge the structs!
|
||||
*/
|
||||
struct RefreshMelt /* FIXME: name to make it clearer this is about ONE coin! */
|
||||
struct RefreshMelt
|
||||
{
|
||||
/**
|
||||
* Information about the coin that is being melted.
|
||||
@ -544,8 +540,15 @@ struct RefreshMelt /* FIXME: name to make it clearer this is about ONE coin! */
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
|
||||
|
||||
/**
|
||||
* Which melting operation should the coin become a part of.
|
||||
*/
|
||||
struct GNUNET_HashCode melt_hash;
|
||||
|
||||
/**
|
||||
* How much value is being melted?
|
||||
* This amount includes the fees, so the final amount contributed
|
||||
* to the melt is this value minus the fee for melting the coin.
|
||||
*/
|
||||
struct TALER_Amount amount;
|
||||
|
||||
|
@ -22,10 +22,6 @@
|
||||
* - actually abstract DB implementation (i.e. via plugin logic)
|
||||
* (this file should remain largely unchanged with the exception
|
||||
* of the PQ-specific DB handle types)
|
||||
* - /refresh/link:
|
||||
* + check low-level API
|
||||
* + separate DB logic from response generation
|
||||
* + check for leaks
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <pthread.h>
|
||||
@ -354,8 +350,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: good place to assert deposit_total > withdraw_total... */
|
||||
GNUNET_break (0 > TALER_amount_cmp (withdraw_total,
|
||||
deposit_total));
|
||||
balance = TALER_amount_subtract (deposit_total,
|
||||
withdraw_total);
|
||||
if (0 < TALER_amount_cmp (amount_required,
|
||||
@ -382,8 +378,6 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
||||
return TALER_MINT_reply_internal_error (connection,
|
||||
"Internal error");
|
||||
}
|
||||
|
||||
// FIXME: can we avoid the cast?
|
||||
collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub;
|
||||
collectable.sig = sig;
|
||||
collectable.reserve_pub = *reserve;
|
||||
@ -430,6 +424,7 @@ static int
|
||||
refresh_accept_melts (struct MHD_Connection *connection,
|
||||
PGconn *db_conn,
|
||||
const struct MintKeyState *key_state,
|
||||
const struct GNUNET_HashCode *melt_hash,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
|
||||
const struct TALER_CoinPublicInfo *coin_public_info,
|
||||
const struct MeltDetails *coin_details,
|
||||
@ -474,6 +469,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
||||
|
||||
melt.coin = *coin_public_info;
|
||||
melt.coin_sig = coin_details->melt_sig;
|
||||
melt.melt_hash = *melt_hash;
|
||||
melt.amount = coin_details->melt_amount;
|
||||
if (GNUNET_OK !=
|
||||
TALER_MINT_DB_insert_refresh_melt (db_conn,
|
||||
@ -496,6 +492,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
||||
* melted and confirm the melting operation to the client.
|
||||
*
|
||||
* @param connection the MHD connection to handle
|
||||
* @param melt_hash hash code of the session the coins are melted into
|
||||
* @param refresh_session_pub public key of the refresh session
|
||||
* @param client_signature signature of the client (matching @a refresh_session_pub)
|
||||
* over the melting request
|
||||
@ -508,6 +505,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
||||
*/
|
||||
int
|
||||
TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
|
||||
const struct GNUNET_HashCode *melt_hash,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||
const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
|
||||
unsigned int num_new_denoms,
|
||||
@ -558,6 +556,7 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
|
||||
(res = refresh_accept_melts (connection,
|
||||
db_conn,
|
||||
key_state,
|
||||
melt_hash,
|
||||
refresh_session_pub,
|
||||
&coin_public_infos[i],
|
||||
&coin_melt_details[i],
|
||||
|
@ -93,7 +93,8 @@ struct MeltDetails
|
||||
|
||||
/**
|
||||
* How much of the coin's value did the client allow to be melted?
|
||||
* (FIXME: are the fees included here!?)
|
||||
* This amount includes the fees, so the final amount contributed
|
||||
* to the melt is this value minus the fee for melting the coin.
|
||||
*/
|
||||
struct TALER_Amount melt_amount;
|
||||
};
|
||||
@ -107,6 +108,7 @@ struct MeltDetails
|
||||
* melted and confirm the melting operation to the client.
|
||||
*
|
||||
* @param connection the MHD connection to handle
|
||||
* @param melt_hash hash code of the session the coins are melted into
|
||||
* @param refresh_session_pub public key of the refresh session
|
||||
* @param client_signature signature of the client (matching @a refresh_session_pub)
|
||||
* over the melting request
|
||||
@ -119,6 +121,7 @@ struct MeltDetails
|
||||
*/
|
||||
int
|
||||
TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
|
||||
const struct GNUNET_HashCode *melt_hash,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||
const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
|
||||
unsigned int num_new_denoms,
|
||||
|
@ -195,9 +195,10 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
||||
&melt_hash);
|
||||
|
||||
body.melt_hash = melt_hash;
|
||||
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT);
|
||||
body.purpose.size = htonl (sizeof (struct RefreshMeltSignatureBody));
|
||||
body.melt_hash = melt_hash;
|
||||
body.amount = TALER_amount_hton (coin_melt_details->melt_amount);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
(res = request_json_check_signature (connection,
|
||||
@ -247,6 +248,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
||||
|
||||
/* FIXME: we must also store the signature over the melt! (#3635) */
|
||||
return TALER_MINT_db_execute_refresh_melt (connection,
|
||||
&melt_hash,
|
||||
refresh_session_pub,
|
||||
NULL, /* FIXME: #3635! */
|
||||
num_new_denoms,
|
||||
|
@ -305,7 +305,7 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
|
||||
dc.merchant = *merchant;
|
||||
TALER_MINT_keys_sign (&dc.purpose,
|
||||
&sig);
|
||||
sig_json = TALER_JSON_from_sig (&dc.purpose, &sig);
|
||||
sig_json = TALER_JSON_from_eddsa_sig (&dc.purpose, &sig);
|
||||
ret = TALER_MINT_reply_json_pack (connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:s, s:o}",
|
||||
@ -332,28 +332,72 @@ TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection,
|
||||
{
|
||||
const struct TALER_MINT_DB_TransactionList *pos;
|
||||
int ret;
|
||||
json_t *history;
|
||||
json_t *transaction;
|
||||
const char *type;
|
||||
struct TALER_Amount value;
|
||||
|
||||
// FIXME: implement properly! (#3632)
|
||||
history = json_array ();
|
||||
for (pos = tl; NULL != pos; pos = pos->next)
|
||||
{
|
||||
switch (pos->type)
|
||||
{
|
||||
case TALER_MINT_DB_TT_DEPOSIT:
|
||||
/* FIXME: add operation details to json reply */
|
||||
break;
|
||||
{
|
||||
struct TALER_DepositRequest dr;
|
||||
const struct Deposit *deposit = pos->details.deposit;
|
||||
|
||||
type = "deposit";
|
||||
value = deposit->amount;
|
||||
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_DEPOSIT);
|
||||
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequest));
|
||||
dr.h_contract = deposit->h_contract;
|
||||
dr.h_wire = deposit->h_wire;
|
||||
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
|
||||
dr.amount = TALER_amount_hton (deposit->amount);
|
||||
dr.coin_pub = deposit->coin.coin_pub;
|
||||
transaction = TALER_JSON_from_ecdsa_sig (&dr.purpose,
|
||||
&deposit->csig);
|
||||
break;
|
||||
}
|
||||
case TALER_MINT_DB_TT_REFRESH_MELT:
|
||||
/* FIXME: add operation details to json reply */
|
||||
{
|
||||
struct RefreshMeltSignatureBody ms;
|
||||
const struct RefreshMelt *melt = pos->details.melt;
|
||||
|
||||
type = "melt";
|
||||
value = melt->amount;
|
||||
ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT);
|
||||
ms.purpose.size = htonl (sizeof (struct RefreshMeltSignatureBody));
|
||||
ms.melt_hash = melt->melt_hash;
|
||||
ms.amount = TALER_amount_hton (melt->amount);
|
||||
transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,
|
||||
&melt->coin_sig);
|
||||
}
|
||||
break;
|
||||
case TALER_MINT_DB_TT_LOCK:
|
||||
/* FIXME: add operation details to json reply */
|
||||
break;
|
||||
{
|
||||
type = "lock";
|
||||
value = pos->details.lock->amount;
|
||||
transaction = NULL;
|
||||
GNUNET_break (0); /* #3625: Lock NOT implemented! */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
json_array_append_new (history,
|
||||
json_pack ("{s:s, s:o}",
|
||||
"type", type,
|
||||
"amount", TALER_JSON_from_amount (value),
|
||||
"signature", transaction));
|
||||
}
|
||||
|
||||
ret = TALER_MINT_reply_json_pack (connection,
|
||||
MHD_HTTP_FORBIDDEN,
|
||||
"{s:s}",
|
||||
"error", "insufficient funds");
|
||||
"{s:s, s:o}",
|
||||
"error", "insufficient funds",
|
||||
"history", history);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -517,7 +561,7 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
|
||||
char *sig_buf;
|
||||
int ret;
|
||||
|
||||
/* FIXME: use TALER_JSON_from_sig here instead!? */
|
||||
/* FIXME: use TALER_JSON_from_eddsa_sig here instead!? */
|
||||
sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,
|
||||
&sig_buf);
|
||||
sig_json = TALER_JSON_from_data (sig_buf,
|
||||
@ -561,7 +605,7 @@ TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
|
||||
body.kappa = htonl (kappa);
|
||||
TALER_MINT_keys_sign (&body.purpose,
|
||||
&sig);
|
||||
sig_json = TALER_JSON_from_sig (&body.purpose, &sig);
|
||||
sig_json = TALER_JSON_from_eddsa_sig (&body.purpose, &sig);
|
||||
ret = TALER_MINT_reply_json_pack (connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:o, s:i}",
|
||||
@ -595,7 +639,7 @@ TALER_MINT_reply_refresh_commit_success (struct MHD_Connection *connection,
|
||||
body.noreveal_index = htons (refresh_session->noreveal_index);
|
||||
TALER_MINT_keys_sign (&body.purpose,
|
||||
&sig);
|
||||
sig_json = TALER_JSON_from_sig (&body.purpose, &sig);
|
||||
sig_json = TALER_JSON_from_eddsa_sig (&body.purpose, &sig);
|
||||
GNUNET_assert (NULL != sig_json);
|
||||
ret = TALER_MINT_reply_json_pack (connection,
|
||||
MHD_HTTP_OK,
|
||||
|
@ -90,8 +90,8 @@ TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp)
|
||||
* @return the JSON reporesentation of the signature with purpose
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
const struct GNUNET_CRYPTO_EddsaSignature *signature)
|
||||
TALER_JSON_from_eddsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
const struct GNUNET_CRYPTO_EddsaSignature *signature)
|
||||
{
|
||||
json_t *root;
|
||||
json_t *el;
|
||||
@ -106,7 +106,37 @@ TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
|
||||
el = TALER_JSON_from_data (signature,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaSignature));
|
||||
json_object_set_new (root, "sig", el);
|
||||
json_object_set_new (root, "eddsa-sig", el);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a signature (with purpose) to a JSON object representation.
|
||||
*
|
||||
* @param purpose purpose of the signature
|
||||
* @param signature the signature
|
||||
* @return the JSON reporesentation of the signature with purpose
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_ecdsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
const struct GNUNET_CRYPTO_EcdsaSignature *signature)
|
||||
{
|
||||
json_t *root;
|
||||
json_t *el;
|
||||
|
||||
root = json_object ();
|
||||
|
||||
el = json_integer ((json_int_t) ntohl (purpose->size));
|
||||
json_object_set_new (root, "size", el);
|
||||
|
||||
el = json_integer ((json_int_t) ntohl (purpose->purpose));
|
||||
json_object_set_new (root, "purpose", el);
|
||||
|
||||
el = TALER_JSON_from_data (signature,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaSignature));
|
||||
json_object_set_new (root, "ecdsa-sig", el);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -133,6 +163,20 @@ TALER_JSON_from_data (const void *data, size_t size)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert binary hash to a JSON string with the base32crockford
|
||||
* encoding.
|
||||
*
|
||||
* @param hc binary data
|
||||
* @return json string that encodes @a hc
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_hash (const struct GNUNET_HashCode *hc)
|
||||
{
|
||||
return TALER_JSON_from_data (hc, sizeof (struct GNUNET_HashCode));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object to Amount
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user