This commit is contained in:
Christian Grothoff 2016-01-17 18:19:09 +01:00
parent 00612f5e19
commit c1f28638c9
9 changed files with 428 additions and 32 deletions

View File

@ -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 GNUNET_NETWORK_STRUCT_END

View File

@ -571,7 +571,7 @@ typedef void
/** /**
* Function called with the results of the lookup of the * Function called with the results of the lookup of the
* wire transfer identifier information. * wire transfer identifier information.
* *
* @param cls closure * @param cls closure
* @param wtid base32-encoded wire transfer identifier, NULL * @param wtid base32-encoded wire transfer identifier, NULL
* if the transaction was not yet done * if the transaction was not yet done
@ -585,6 +585,31 @@ typedef void
const char *wtid, const char *wtid,
struct GNUNET_TIME_Absolute execution_time); 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. * @brief The plugin API, returned from the plugin's "init" function.
* The argument given to "init" is simply a configuration handle. * The argument given to "init" is simply a configuration handle.
@ -1194,11 +1219,30 @@ struct TALER_MINTDB_Plugin
struct TALER_MINTDB_TransactionList *list); struct TALER_MINTDB_TransactionList *list);
/**
* 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. * Try to find the wire transfer details for a deposit operation.
* If we did not execute the deposit yet, return when it is supposed * If we did not execute the deposit yet, return when it is supposed
* to be executed. * to be executed.
* *
* @param cls closure * @param cls closure
* @param h_contract hash of the contract * @param h_contract hash of the contract
* @param h_wire hash of merchant wire details * @param h_wire hash of merchant wire details

View File

@ -106,6 +106,11 @@
*/ */
#define TALER_SIGNATURE_MINT_WIRE_TYPES 1036 #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 */ /* 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 GNUNET_NETWORK_STRUCT_END

View File

@ -1551,10 +1551,190 @@ 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. * 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 * Function called with the results of the lookup of the
* wire transfer identifier information. * wire transfer identifier information.
* *
* @param cls our context for transmission * @param cls our context for transmission
* @param wtid base32-encoded wire transfer identifier, NULL * @param wtid base32-encoded wire transfer identifier, NULL
* if the transaction was not yet done * if the transaction was not yet done
@ -1590,16 +1770,19 @@ handle_wtid_data (void *cls,
if (NULL == wtid) 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) execution_time.abs_value_us)
ctx->res = TMH_RESPONSE_reply_deposit_unknown (ctx->connection); ctx->res = TMH_RESPONSE_reply_deposit_unknown (ctx->connection);
else else
ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection); ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection,
execution_time);
} }
else 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; struct DepositWtidContext ctx;
ctx.connection = connection; ctx.connection = connection;
ctx.res = MHD_NO; /* this value should never be read... */
ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls, ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls,
h_contract, h_contract,
h_wire, h_wire,
@ -1634,7 +1818,7 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
merchant_pub, merchant_pub,
transaction_id, transaction_id,
&handle_wtid_data, &handle_wtid_data,
connection); &ctx);
if (GNUNET_SYSERR == ret) if (GNUNET_SYSERR == ret)
{ {
GNUNET_break (0); GNUNET_break (0);

View File

@ -192,6 +192,19 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
json_t *wire); json_t *wire);
/**
* 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 * Execute a "/deposit/wtid". Returns the transfer information
* associated with the given deposit. * associated with the given deposit.
@ -212,5 +225,6 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantPublicKeyP *merchant_pub,
uint64_t transaction_id); uint64_t transaction_id);
#endif #endif
/* TALER_MINT_HTTPD_DB_H */ /* TALER_MINT_HTTPD_DB_H */

View File

@ -1056,15 +1056,15 @@ TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
* 404 reply. * 404 reply.
* *
* @param connection connection to the client * @param connection connection to the client
* @param
* @return MHD result code * @return MHD result code
*/ */
int 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 TMH_RESPONSE_reply_json_pack (connection,
return MHD_NO; 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. * we did not execute the deposit yet. Generate a 202 reply.
* *
* @param connection connection to the client * @param connection connection to the client
* @param * @param planned_exec_time planned execution time
* @return MHD result code * @return MHD result code
*/ */
int int
TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
...) struct GNUNET_TIME_Absolute planned_exec_time)
{ {
GNUNET_break (0); // FIXME: not implemented return TMH_RESPONSE_reply_json_pack (connection,
return MHD_NO; 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. * them. Generates the 200 reply.
* *
* @param connection connection to the client * @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 * @return MHD result code
*/ */
int int
TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, 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 GNUNET_break (0); // FIXME: not implemented
return MHD_NO; return MHD_NO;
} }
/* end of taler-mint-httpd_responses.c */ /* end of taler-mint-httpd_responses.c */

View File

@ -253,12 +253,10 @@ TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection
* 404 reply. * 404 reply.
* *
* @param connection connection to the client * @param connection connection to the client
* @param
* @return MHD result code * @return MHD result code
*/ */
int 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. * we did not execute the deposit yet. Generate a 202 reply.
* *
* @param connection connection to the client * @param connection connection to the client
* @param * @param planned_exec_time planned execution time
* @return MHD result code * @return MHD result code
*/ */
int int
TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, 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. * them. Generates the 200 reply.
* *
* @param connection connection to the client * @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 * @return MHD result code
*/ */
int int
TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, 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);
/** /**

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER 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 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 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, const char *upload_data,
size_t *upload_data_size) size_t *upload_data_size)
{ {
GNUNET_break (0); // not implemented struct TALER_WireTransferIdentifierP wtid;
return MHD_NO; 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 connection the MHD connection to handle
* @param tps signed request to execute * @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 merchant_sig signature from the merchant (to be checked)
* @param transaction_id transaction ID (in host byte order) * @param transaction_id transaction ID (in host byte order)
* @return MHD result code * @return MHD result code

View File

@ -3364,11 +3364,34 @@ 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. * Try to find the wire transfer details for a deposit operation.
* If we did not execute the deposit yet, return when it is supposed * If we did not execute the deposit yet, return when it is supposed
* to be executed. * to be executed.
* *
* @param cls closure * @param cls closure
* @param h_contract hash of the contract * @param h_contract hash of the contract
* @param h_wire hash of merchant wire details * @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_transfer = &postgres_get_transfer;
plugin->get_coin_transactions = &postgres_get_coin_transactions; plugin->get_coin_transactions = &postgres_get_coin_transactions;
plugin->free_coin_transaction_list = &common_free_coin_transaction_list; 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; plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid;
return plugin; return plugin;
} }