diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-01-17 18:19:09 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-01-17 18:19:09 +0100 |
commit | c1f28638c9929424f9ad395c7016e6ea2022d751 (patch) | |
tree | c99637be9f515bee58f2791f74f3f70f11e29c68 | |
parent | 00612f5e19582db782832c69d093049c5f75dd9b (diff) | |
download | exchange-c1f28638c9929424f9ad395c7016e6ea2022d751.tar.xz |
working on #3888
-rw-r--r-- | src/include/taler_crypto_lib.h | 31 | ||||
-rw-r--r-- | src/include/taler_mintdb_plugin.h | 48 | ||||
-rw-r--r-- | src/include/taler_signatures.h | 19 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 198 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.h | 14 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 67 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.h | 33 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_tracking.c | 24 | ||||
-rw-r--r-- | src/mintdb/plugin_mintdb_postgres.c | 26 |
9 files changed, 428 insertions, 32 deletions
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 16240e5a3..87020fbbe 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -428,6 +428,37 @@ struct TALER_RefreshLinkDecrypted }; +/** + * Binary information encoded in Crockford's Base32 in wire transfer + * subjects of transfers from Taler to a merchant. The actual value + * is chosen by the mint and has no particular semantics, other than + * being unique so that the mint can lookup details about the wire + * transfer when needed. + */ +struct TALER_WireTransferIdentifierP +{ + + /** + * Raw value. Note that typical payment systems (SEPA, ACH) support + * at least two lines of 27 ASCII characters to encode a transaction + * subject or "details", for a total of 54 characters. (The payment + * system protocols often support more lines, but the forms presented + * to customers are usually limited to 54 characters.) + * + * With a Base32-encoding of 5 bit per character, this gives us 270 + * bits or (rounded down) 33 bytes. So we use the first 32 bytes to + * encode the actual value (i.e. a 256-bit / 32-byte public key or + * a hash code), and the last byte for a minimalistic checksum. + */ + uint8_t raw[32]; + + /** + * Checksum using CRC8 over the @e raw data. + */ + uint8_t crc8; +}; + + GNUNET_NETWORK_STRUCT_END diff --git a/src/include/taler_mintdb_plugin.h b/src/include/taler_mintdb_plugin.h index d9a1c6c85..a4a94faa9 100644 --- a/src/include/taler_mintdb_plugin.h +++ b/src/include/taler_mintdb_plugin.h @@ -571,7 +571,7 @@ typedef void /** * Function called with the results of the lookup of the * wire transfer identifier information. - * + * * @param cls closure * @param wtid base32-encoded wire transfer identifier, NULL * if the transaction was not yet done @@ -585,6 +585,31 @@ typedef void const char *wtid, struct GNUNET_TIME_Absolute execution_time); + +/** + * Function called with the results of the lookup of the + * transaction data associated with a wire transfer identifier. + * + * @param cls closure + * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) + * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) + * @param h_contract which contract was this payment about + * @param transaction_id merchant's transaction ID for the payment + * @param coin_pub which public key was this payment about + * @param deposit_value amount contributed by this coin in total + * @param deposit_fee deposit fee charged by mint for this coin + */ +typedef void +(*TALER_MINTDB_TransactionDataCallback)(void *cls, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *deposit_value, + const struct TALER_Amount *deposit_fee); + + /** * @brief The plugin API, returned from the plugin's "init" function. * The argument given to "init" is simply a configuration handle. @@ -1195,10 +1220,29 @@ struct TALER_MINTDB_Plugin /** + * Lookup the list of Taler transactions that was aggregated + * into a wire transfer by the respective @a raw_wtid. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param raw_wtid the raw wire transfer identifier we used + * @param raw_len number of bytes in @a raw_wtid (right now always 32) + * @param cb function to call on each transaction found + * @param cb_cls closure for @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors + */ + int + (*lookup_wire_transactions) (void *cls, + const void *raw_wtid, + size_t raw_len, + TALER_MINTDB_TransactionDataCallback cb, + void *cb_cls); + + + /** * Try to find the wire transfer details for a deposit operation. * If we did not execute the deposit yet, return when it is supposed * to be executed. - * + * * @param cls closure * @param h_contract hash of the contract * @param h_wire hash of merchant wire details diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index fb2916cff..ca8cf2dec 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -106,6 +106,11 @@ */ #define TALER_SIGNATURE_MINT_WIRE_TYPES 1036 +/** + * Signature where the Mint confirms the /deposit/wtid response. + */ +#define TALER_SIGNATURE_MINT_CONFIRM_WIRE 1036 + /*********************/ /* Wallet signatures */ @@ -863,6 +868,20 @@ struct TALER_ContractPS }; +/** + * Details affirmed by the mint about a wire transfer the mint + * claims to have done with respect to a deposit operation. + */ +struct TALER_ConfirmWirePS +{ + /** + * Purpose header for the signature over the contract with + * purpose #TALER_SIGNATURE_MINT_CONFIRM_WIRE. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + +}; GNUNET_NETWORK_STRUCT_END diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index 2b4ade595..1b0af585d 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -1552,9 +1552,189 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, /** + * Closure for #handle_transaction_data. + */ +struct WtidTransactionContext +{ + + /** + * Total amount of the wire transfer, as calculated by + * summing up the individual amounts. To be rounded down + * to calculate the real transfer amount at the end. + * Only valid if @e is_valid is #GNUNET_YES. + */ + struct TALER_Amount total; + + /** + * Public key of the merchant, only valid if @e is_valid + * is #GNUNET_YES. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Hash of the wire details of the merchant (identical for all + * deposits), only valid if @e is_valid is #GNUNET_YES. + */ + struct GNUNET_HashCode h_wire; + + /** + * JSON array with details about the individual deposits. + */ + json_t *deposits; + + /** + * Initially #GNUNET_NO, if we found no deposits so far. Set to + * #GNUNET_YES if we got transaction data, and the database replies + * remained consistent with respect to @e merchant_pub and @e h_wire + * (as they should). Set to #GNUNET_SYSERR if we encountered an + * internal error. + */ + int is_valid; + +}; + + +/** + * Function called with the results of the lookup of the + * transaction data for the given wire transfer identifier. + * + * @param cls our context for transmission + * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) + * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) + * @param h_contract which contract was this payment about + * @param transaction_id merchant's transaction ID for the payment + * @param coin_pub which public key was this payment about + * @param deposit_value amount contributed by this coin in total + * @param deposit_fee deposit fee charged by mint for this coin + */ +static void +handle_transaction_data (void *cls, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *deposit_value, + const struct TALER_Amount *deposit_fee) +{ + struct WtidTransactionContext *ctx = cls; + struct TALER_Amount delta; + + if (GNUNET_SYSERR == ctx->is_valid) + return; + if (GNUNET_NO == ctx->is_valid) + { + ctx->merchant_pub = *merchant_pub; + ctx->h_wire = *h_wire; + ctx->is_valid = GNUNET_YES; + if (GNUNET_OK != + TALER_amount_subtract (&ctx->total, + deposit_value, + deposit_fee)) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + } + else + { + if ( (0 != memcmp (&ctx->merchant_pub, + merchant_pub, + sizeof (struct TALER_MerchantPublicKeyP))) || + (0 != memcmp (&ctx->h_wire, + h_wire, + sizeof (struct GNUNET_HashCode))) ) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + TALER_amount_subtract (&delta, + deposit_value, + deposit_fee)) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + TALER_amount_add (&ctx->total, + &ctx->total, + &delta)) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + } + /* NOTE: We usually keep JSON stuff out of the _DB file, and this + is also ugly if we ever add signatures over this data. (#4135) */ + json_array_append (ctx->deposits, + json_pack ("{s:o, s:o, s:o, s:I, s:o}", + "deposit_value", TALER_json_from_amount (deposit_value), + "deposit_fee", TALER_json_from_amount (deposit_fee), + "H_contract", TALER_json_from_data (h_contract, + sizeof (struct GNUNET_HashCode)), + "transaction_id", (json_int_t) transaction_id, + "coin_pub", TALER_json_from_data (coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)))); +} + + +/** + * Execute a "/wire/deposits". Returns the transaction information + * associated with the given wire transfer identifier. + * + * @param connection the MHD connection to handle + * @param wtid wire transfer identifier to resolve + * @return MHD result code + */ +int +TMH_DB_execute_wire_deposits (struct MHD_Connection *connection, + const struct TALER_WireTransferIdentifierP *wtid) +{ + int ret; + struct WtidTransactionContext ctx; + + ctx.is_valid = GNUNET_NO; + ctx.deposits = json_array (); + ret = TMH_plugin->lookup_wire_transactions (TMH_plugin->cls, + &wtid->raw, + sizeof (wtid->raw), + &handle_transaction_data, + &ctx); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + json_decref (ctx.deposits); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + if (GNUNET_SYSERR == ctx.is_valid) + { + GNUNET_break (0); + json_decref (ctx.deposits); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + if (GNUNET_NO == ctx.is_valid) + { + json_decref (ctx.deposits); + return TMH_RESPONSE_reply_arg_unknown (connection, + "wtid"); + } + return TMH_RESPONSE_reply_wire_deposit_details (connection, + &ctx.total, + &ctx.merchant_pub, + &ctx.h_wire, + ctx.deposits); +} + + +/** * Closure for #handle_wtid_data. */ -struct DepositWtidContext +struct DepositWtidContext { /** @@ -1572,7 +1752,7 @@ struct DepositWtidContext /** * Function called with the results of the lookup of the * wire transfer identifier information. - * + * * @param cls our context for transmission * @param wtid base32-encoded wire transfer identifier, NULL * if the transaction was not yet done @@ -1590,16 +1770,19 @@ handle_wtid_data (void *cls, if (NULL == wtid) { - if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == + if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == execution_time.abs_value_us) ctx->res = TMH_RESPONSE_reply_deposit_unknown (ctx->connection); else - ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection); + ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection, + execution_time); } else { - ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection); - } + ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection, + wtid, + execution_time); + } } @@ -1627,6 +1810,7 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, struct DepositWtidContext ctx; ctx.connection = connection; + ctx.res = MHD_NO; /* this value should never be read... */ ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls, h_contract, h_wire, @@ -1634,7 +1818,7 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, merchant_pub, transaction_id, &handle_wtid_data, - connection); + &ctx); if (GNUNET_SYSERR == ret) { GNUNET_break (0); diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h index d9adba2d9..0ee3d0509 100644 --- a/src/mint/taler-mint-httpd_db.h +++ b/src/mint/taler-mint-httpd_db.h @@ -193,6 +193,19 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, /** + * Execute a "/wire/deposits". Returns the transaction information + * associated with the given wire transfer identifier. + * + * @param connection the MHD connection to handle + * @param wtid wire transfer identifier to resolve + * @return MHD result code + */ +int +TMH_DB_execute_wire_deposits (struct MHD_Connection *connection, + const struct TALER_WireTransferIdentifierP *wtid); + + +/** * Execute a "/deposit/wtid". Returns the transfer information * associated with the given deposit. * @@ -212,5 +225,6 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, const struct TALER_MerchantPublicKeyP *merchant_pub, uint64_t transaction_id); + #endif /* TALER_MINT_HTTPD_DB_H */ diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c index f3498b469..9a55d5aab 100644 --- a/src/mint/taler-mint-httpd_responses.c +++ b/src/mint/taler-mint-httpd_responses.c @@ -1056,15 +1056,15 @@ TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, * 404 reply. * * @param connection connection to the client - * @param * @return MHD result code */ int -TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection, - ...) +TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection) { - GNUNET_break (0); // FIXME: not implemented - return MHD_NO; + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", "Deposit unknown"); } @@ -1073,15 +1073,17 @@ TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection, * we did not execute the deposit yet. Generate a 202 reply. * * @param connection connection to the client - * @param + * @param planned_exec_time planned execution time * @return MHD result code */ int TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, - ...) + struct GNUNET_TIME_Absolute planned_exec_time) { - GNUNET_break (0); // FIXME: not implemented - return MHD_NO; + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_FOUND, + "{s:o}", + "execution_time", TALER_json_from_abs (planned_exec_time)); } @@ -1090,15 +1092,58 @@ TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, * them. Generates the 200 reply. * * @param connection connection to the client - * @param + * @param wtid wire transfer identifier (as 0-terminated string) + * @param exec_time execution time of the wire transfer * @return MHD result code */ int TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, - ...) + const char *wtid, + struct GNUNET_TIME_Absolute exec_time) +{ + struct TALER_ConfirmWirePS cw; + struct TALER_MintPublicKeyP pub; + struct TALER_MintSignatureP sig; + + cw.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE); + cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS)); + // FIXME: fill in rest of 'cw'! + TMH_KS_sign (&cw.purpose, + &pub, + &sig); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_FOUND, + "{s:s, s:o, s:o, s:o}", + "wtid", wtid, + "execution_time", TALER_json_from_abs (exec_time), + "mint_sig", TALER_json_from_data (&sig, + sizeof (sig)), + "mint_pub", TALER_json_from_data (&pub, + sizeof (pub))); +} + + +/** + * A merchant asked for transaction details about a wire transfer. + * Provide them. Generates the 200 reply. + * + * @param connection connection to the client + * @param total total amount that was transferred + * @param merchant_pub public key of the merchant + * @param h_wire destination account + * @param deposits details about the combined deposits + * @return MHD result code + */ +int +TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection, + const struct TALER_Amount *total, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + json_t *deposits) { GNUNET_break (0); // FIXME: not implemented return MHD_NO; } + /* end of taler-mint-httpd_responses.c */ diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h index 5d1523b4b..6debbc935 100644 --- a/src/mint/taler-mint-httpd_responses.h +++ b/src/mint/taler-mint-httpd_responses.h @@ -253,12 +253,10 @@ TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection * 404 reply. * * @param connection connection to the client - * @param * @return MHD result code */ int -TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection, - ...); +TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection); /** @@ -266,12 +264,12 @@ TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection, * we did not execute the deposit yet. Generate a 202 reply. * * @param connection connection to the client - * @param + * @param planned_exec_time planned execution time * @return MHD result code */ int TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, - ...); + struct GNUNET_TIME_Absolute planned_exec_time); /** @@ -279,12 +277,33 @@ TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, * them. Generates the 200 reply. * * @param connection connection to the client - * @param + * @param wtid wire transfer identifier (as 0-terminated string) + * @param exec_time execution time of the wire transfer * @return MHD result code */ int TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, - ...); + const char *wtid, + struct GNUNET_TIME_Absolute exec_time); + + +/** + * A merchant asked for transaction details about a wire transfer. + * Provide them. Generates the 200 reply. + * + * @param connection connection to the client + * @param total total amount that was transferred + * @param merchant_pub public key of the merchant + * @param h_wire destination account + * @param deposits details about the combined deposits + * @return MHD result code + */ +int +TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection, + const struct TALER_Amount *total, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + json_t *deposits); /** diff --git a/src/mint/taler-mint-httpd_tracking.c b/src/mint/taler-mint-httpd_tracking.c index 59d029429..e61b4bae1 100644 --- a/src/mint/taler-mint-httpd_tracking.c +++ b/src/mint/taler-mint-httpd_tracking.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. + Copyright (C) 2014, 2015, 2016 GNUnet e.V. 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 @@ -46,8 +46,24 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, const char *upload_data, size_t *upload_data_size) { - GNUNET_break (0); // not implemented - return MHD_NO; + struct TALER_WireTransferIdentifierP wtid; + int res; + + res = TMH_PARSE_mhd_request_arg_data (connection, + "wtid", + &wtid, + sizeof (struct TALER_WireTransferIdentifierP)); + if (GNUNET_SYSERR == res) + return MHD_NO; /* internal error */ + if (GNUNET_NO == res) + return MHD_YES; /* parse error */ + if (wtid.crc8 != + GNUNET_CRYPTO_crc8_n (&wtid.raw, + sizeof (wtid.raw))) + return TMH_RESPONSE_reply_arg_invalid (connection, + "wtid"); + return TMH_DB_execute_wire_deposits (connection, + &wtid); } @@ -57,7 +73,7 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, * * @param connection the MHD connection to handle * @param tps signed request to execute - * @param merchant_pub public key from the merchant + * @param merchant_pub public key from the merchant * @param merchant_sig signature from the merchant (to be checked) * @param transaction_id transaction ID (in host byte order) * @return MHD result code diff --git a/src/mintdb/plugin_mintdb_postgres.c b/src/mintdb/plugin_mintdb_postgres.c index 0f32cfb8e..2ebc8f0ff 100644 --- a/src/mintdb/plugin_mintdb_postgres.c +++ b/src/mintdb/plugin_mintdb_postgres.c @@ -3365,10 +3365,33 @@ postgres_get_coin_transactions (void *cls, /** + * Lookup the list of Taler transactions that was aggregated + * into a wire transfer by the respective @a raw_wtid. + * + * @param cls closure + * @param raw_wtid the raw wire transfer identifier we used + * @param raw_len number of bytes in @a raw_wtid (right now always 32) + * @param cb function to call on each transaction found + * @param cb_cls closure for @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors + */ +static int +postgres_lookup_wire_transactions (void *cls, + const void *raw_wtid, + size_t raw_len, + TALER_MINTDB_TransactionDataCallback cb, + void *cb_cls) +{ + GNUNET_break (0); // not implemented! + return GNUNET_SYSERR; +} + + +/** * Try to find the wire transfer details for a deposit operation. * If we did not execute the deposit yet, return when it is supposed * to be executed. - * + * * @param cls closure * @param h_contract hash of the contract * @param h_wire hash of merchant wire details @@ -3465,6 +3488,7 @@ libtaler_plugin_mintdb_postgres_init (void *cls) plugin->get_transfer = &postgres_get_transfer; plugin->get_coin_transactions = &postgres_get_coin_transactions; plugin->free_coin_transaction_list = &common_free_coin_transaction_list; + plugin->lookup_wire_transactions = &postgres_lookup_wire_transactions; plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid; return plugin; } |