diff options
Diffstat (limited to 'src/mint/taler-mint-httpd_db.c')
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 278 |
1 files changed, 251 insertions, 27 deletions
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index 7a78f93e..f3a22911 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -25,12 +25,15 @@ * - /deposit: check for leaks */ #include "platform.h" +#include <pthread.h> +#include <jansson.h> #include "taler-mint-httpd_db.h" #include "taler_signatures.h" +#include "taler-mint-httpd_keys.h" #include "taler-mint-httpd_responses.h" #include "mint_db.h" #include "mint.h" -#include <pthread.h> +#include "taler_json_lib.h" /** @@ -48,43 +51,39 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, const struct Deposit *deposit) { PGconn *db_conn; + struct Deposit *existing_deposit; + int res; if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) { GNUNET_break (0); return TALER_MINT_reply_internal_error (connection, - "Failed to connect to database\n"); + "Failed to connect to database"); } - + res = TALER_MINT_DB_get_deposit (db_conn, + &deposit->coin_pub, + &existing_deposit); + if (GNUNET_YES == res) { - struct Deposit *existing_deposit; - int res; - - res = TALER_MINT_DB_get_deposit (db_conn, - &deposit->coin_pub, - &existing_deposit); - if (GNUNET_YES == res) - { - // FIXME: memory leak - // FIXME: memcmp will not actually work here - if (0 == memcmp (existing_deposit, deposit, sizeof (struct Deposit))) - return TALER_MINT_reply_deposit_success (connection, deposit); - // FIXME: in the future, check if there's enough credits - // left on the coin. For now: refuse - // FIXME: return more information here - return TALER_MINT_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s}", - "error", - "double spending"); - } + // FIXME: memory leak + // FIXME: memcmp will not actually work here + if (0 == memcmp (existing_deposit, deposit, sizeof (struct Deposit))) + return TALER_MINT_reply_deposit_success (connection, deposit); + // FIXME: in the future, check if there's enough credits + // left on the coin. For now: refuse + // FIXME: return more information here + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s}", + "error", + "double spending"); + } - if (GNUNET_SYSERR == res) - { + if (GNUNET_SYSERR == res) + { GNUNET_break (0); /* FIXME: return error message to client via MHD! */ return MHD_NO; - } } { @@ -133,3 +132,228 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, TALER_MINT_DB_commit (db_conn); return TALER_MINT_reply_deposit_success (connection, deposit); } + + +/** + * Sign a reserve's status with the current signing key. + * FIXME: not sure why we do this. Should just return + * existing list of operations on the reserve. + * + * @param reserve the reserve to sign + * @param key_state the key state containing the current + * signing private key + */ +static void +sign_reserve (struct Reserve *reserve, + struct MintKeyState *key_state) +{ + reserve->status_sign_pub = key_state->current_sign_key_issue.issue.signkey_pub; + reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS); + reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) - + offsetof (struct Reserve, status_sig_purpose)); + GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv, + &reserve->status_sig_purpose, + &reserve->status_sig); +} + + +/** + * Execute a /withdraw/status. + * + * @param connection the MHD connection to handle + * @param reserve_pub public key of the reserve to check + * @return MHD result code + */ +int +TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection, + const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub) +{ + PGconn *db_conn; + int res; + struct Reserve reserve; + struct MintKeyState *key_state; + int must_update = GNUNET_NO; + + + if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + { + GNUNET_break (0); + return TALER_MINT_reply_internal_error (connection, + "Failed to connect to database"); + } + res = TALER_MINT_DB_get_reserve (db_conn, + reserve_pub, + &reserve); + /* check if these are really the matching error codes, + seems odd... */ + if (GNUNET_SYSERR == res) + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "Reserve not found"); + if (GNUNET_OK != res) + { + GNUNET_break (0); + return TALER_MINT_reply_internal_error (connection, + "Internal error"); + } + key_state = TALER_MINT_key_state_acquire (); + if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub, + &reserve.status_sign_pub, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) + { + sign_reserve (&reserve, key_state); + must_update = GNUNET_YES; + } + if ((GNUNET_YES == must_update) && + (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update))) + { + GNUNET_break (0); + return MHD_YES; + } + return TALER_MINT_reply_withdraw_status_success (connection, + &reserve); +} + + +/** + * Execute a /withdraw/sign. + * + * @param connection the MHD connection to handle + * @param wsrd_ro details about the withdraw request + * @return MHD result code + */ +int +TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, + const struct TALER_WithdrawRequest *wsrd_ro) +{ + PGconn *db_conn; + struct Reserve reserve; + struct MintKeyState *key_state; + struct CollectableBlindcoin collectable; + struct TALER_MINT_DenomKeyIssuePriv *dki; + struct TALER_RSA_Signature ev_sig; + struct TALER_Amount amount_required; + /* FIXME: the fact that we do this here is a sign that we + need to have different versions of this struct for + the different places it is used! */ + struct TALER_WithdrawRequest wsrd = *wsrd_ro; + int res; + + if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + { + // FIXME: return 'internal error'? + GNUNET_break (0); + return MHD_NO; + } + + + res = TALER_MINT_DB_get_collectable_blindcoin (db_conn, + &wsrd.coin_envelope, + &collectable); + if (GNUNET_SYSERR == res) + { + // FIXME: return 'internal error' + GNUNET_break (0); + return MHD_NO; + } + + /* Don't sign again if we have already signed the coin */ + if (GNUNET_YES == res) + return TALER_MINT_reply_withdraw_sign_success (connection, + &collectable); + GNUNET_assert (GNUNET_NO == res); + res = TALER_MINT_DB_get_reserve (db_conn, + &wsrd.reserve_pub, + &reserve); + if (GNUNET_SYSERR == res) + { + // FIXME: return 'internal error' + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "Reserve not found"); + + // fill out all the missing info in the request before + // we can check the signature on the request + + wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW); + wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest) - + offsetof (struct TALER_WithdrawRequest, purpose)); + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WITHDRAW, + &wsrd.purpose, + &wsrd.sig, + &wsrd.reserve_pub)) + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_UNAUTHORIZED, + "{s:s}", + "error", "Invalid Signature"); + + key_state = TALER_MINT_key_state_acquire (); + dki = TALER_MINT_get_denom_key (key_state, + &wsrd.denomination_pub); + TALER_MINT_key_state_release (key_state); + if (NULL == dki) + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "Denomination not found"); + + amount_required = TALER_amount_ntoh (dki->issue.value); + amount_required = TALER_amount_add (amount_required, + TALER_amount_ntoh (dki->issue.fee_withdraw)); + + if (0 < TALER_amount_cmp (amount_required, + TALER_amount_ntoh (reserve.balance))) + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_PAYMENT_REQUIRED, + "{s:s}", + "error", + "Insufficient funds"); + if (GNUNET_OK != + TALER_RSA_sign (dki->denom_priv, + &wsrd.coin_envelope, + sizeof (struct TALER_RSA_BlindedSignaturePurpose), + &ev_sig)) + { + // FIXME: return 'internal error' + GNUNET_break (0); + return MHD_NO; + } + + reserve.balance = TALER_amount_hton (TALER_amount_subtract (TALER_amount_ntoh (reserve.balance), + amount_required)); + if (GNUNET_OK != + TALER_MINT_DB_update_reserve (db_conn, + &reserve, + GNUNET_YES)) + { + // FIXME: return 'internal error' + GNUNET_break (0); + return MHD_NO; + } + + collectable.ev = wsrd.coin_envelope; + collectable.ev_sig = ev_sig; + collectable.reserve_pub = wsrd.reserve_pub; + collectable.reserve_sig = wsrd.sig; + if (GNUNET_OK != + TALER_MINT_DB_insert_collectable_blindcoin (db_conn, + &collectable)) + { + // FIXME: return 'internal error' + GNUNET_break (0); + return GNUNET_NO;; + } + return TALER_MINT_reply_withdraw_sign_success (connection, + &collectable); +} |