commit ff8c5abc7448b282a50f931df4ac9184c93bc818
parent 9f969c1bbea784d81eb231b3f7b82efd46093ea7
Author: Marcello Stanisci <marcello.stanisci@inria.fr>
Date: Wed, 16 Sep 2015 16:44:58 +0200
fixing 3966 and refactoring the way
the HTTP server handles malformed queries.
Diffstat:
5 files changed, 109 insertions(+), 136 deletions(-)
diff --git a/src/backend-lib/taler-merchant-httpd_contract.c b/src/backend-lib/taler-merchant-httpd_contract.c
@@ -51,12 +51,11 @@ hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire)
/**
* Take from the frontend the (partly) generated contract and fill
* the missing values in it; for example, the SEPA-aware values.
-* Moreover, it stores the contract in the DB and does the signature of it.
+* Moreover, it stores the contract in the DB.
* @param contract parsed contract, originated by the frontend
* @param db_conn the handle to the local DB
-* @param kpriv merchant's private key
* @param wire merchant's bank's details
-* @param sig where to store the signature
+* @param sig where to store the (subset of the) contract to be signed
* @return pointer to the complete JSON; NULL upon errors
*/
@@ -64,11 +63,10 @@ hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire)
of the contract. To expand to the full fledged version */
json_t *
-MERCHANT_handle_contract (json_t *contract,
+MERCHANT_handle_contract (json_t *j_contract,
PGconn *db_conn,
- struct GNUNET_CRYPTO_EddsaPrivateKey *kpriv,
const struct MERCHANT_WIREFORMAT_Sepa *wire,
- struct GNUNET_CRYPTO_EddsaSignature *sig)
+ struct ContractNBO *contract)
{
json_t *root;
json_t *j_details;
@@ -88,7 +86,6 @@ MERCHANT_handle_contract (json_t *contract,
struct GNUNET_TIME_Absolute timestamp;
struct TALER_Amount amount;
struct TALER_AmountNBO amount_nbo;
- struct ContractNBO contract_nbo;
nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
// timing mgmt
@@ -105,14 +102,16 @@ MERCHANT_handle_contract (json_t *contract,
jh_wire = json_string (h_wire_enc);
#ifdef DEBUG
- str = json_dumps (contract, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
+ str = json_dumps (j_contract, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
#endif
- json_unpack (contract, "{s:o, s:I, s:o}",
- "amount", &j_amount,
- "trans_id", &j_trans_id,
- "details", &j_details);
+ if (-1 == json_unpack (j_contract, "{s:o, s:I, s:o}",
+ "amount", &j_amount,
+ "trans_id", &j_trans_id,
+ "details", &j_details))
+
+ return NULL;
/* needed for DB stuff */
TALER_json_to_amount (j_amount, &amount);
@@ -137,16 +136,15 @@ MERCHANT_handle_contract (json_t *contract,
a,
nounce,
product_id));
- contract_nbo.h_wire = h_wire;
+ contract->h_wire = h_wire;
TALER_amount_hton (&amount_nbo, &amount);
- contract_nbo.amount = amount_nbo;
- contract_nbo.t = GNUNET_TIME_absolute_hton (timestamp);
- contract_nbo.m = GNUNET_htonll ((uint64_t) j_trans_id); // safe?
- GNUNET_CRYPTO_hash (a, strlen (a) + 1, &contract_nbo.h_contract_details);
+ contract->amount = amount_nbo;
+ contract->t = GNUNET_TIME_absolute_hton (timestamp);
+ contract->m = GNUNET_htonll ((uint64_t) j_trans_id); // safe?
+ GNUNET_CRYPTO_hash (a, strlen (a) + 1, &contract->h_contract_details);
free (a);
- contract_nbo.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
- contract_nbo.purpose.size = htonl (sizeof (struct ContractNBO));
- GNUNET_CRYPTO_eddsa_sign (kpriv, &contract_nbo.purpose, sig);
+ contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
+ contract->purpose.size = htonl (sizeof (struct ContractNBO));
return root;
}
diff --git a/src/backend-lib/taler_merchant_contract_lib.h b/src/backend-lib/taler_merchant_contract_lib.h
@@ -55,8 +55,7 @@ GNUNET_NETWORK_STRUCT_END
of the contract. To expand to the full fledged version */
json_t *
-MERCHANT_handle_contract (json_t *contract,
+MERCHANT_handle_contract (json_t *j_contract,
PGconn *db_conn,
- struct GNUNET_CRYPTO_EddsaPrivateKey *kpriv,
const struct MERCHANT_WIREFORMAT_Sepa *wire,
- struct GNUNET_CRYPTO_EddsaSignature *sig);
+ struct ContractNBO *contract);
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
@@ -23,14 +23,14 @@
#include "platform.h"
#include <microhttpd.h>
#include <jansson.h>
-#include <gnunet/gnunet_crypto_lib.h>
#include <gnunet/gnunet_util_lib.h>
#include <taler/taler_json_lib.h>
#include <taler/taler_mint_service.h>
#include "taler-mint-httpd_parsing.h"
#include "taler-mint-httpd_responses.h"
-#include "taler_merchant_lib.h"
+#include "merchant_db.h"
#include "merchant.h"
+#include "taler_merchant_lib.h"
extern struct MERCHANT_WIREFORMAT_Sepa *
TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg);
@@ -59,6 +59,11 @@ static long long unsigned port;
struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
/**
+ * File holding the merchant's private key
+ */
+char *keyfile;
+
+/**
* The MHD Daemon
*/
static struct MHD_Daemon *mhd;
@@ -124,6 +129,7 @@ struct Mint
*/
static struct GNUNET_CONTAINER_MultiPeerMap *mints_map;
+#if FUTURE_USE
/**
* Return the given message to the other end of connection
* @msg (0-terminated) message to show
@@ -146,6 +152,7 @@ generate_message (struct MHD_Response **resp, const char *msg) // this parameter
}
+#endif
/**
* Generate the 'hello world' response
@@ -170,6 +177,7 @@ generate_hello (struct MHD_Response **resp) // this parameter was preceded by a
}
+#ifdef PANIC_MGMT
/**
* Callback for catching serious error conditions from MHD.
*
@@ -190,6 +198,7 @@ mhd_panic_cb (void *cls,
result = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
}
+#endif
/**
* Manage a non 200 HTTP status. I.e. it shows a 'failure' page to
@@ -215,7 +224,7 @@ failure_resp (struct MHD_Connection *connection, unsigned int status)
</center></body></html>";
static char page_MHD_HTTP_METHOD_NOT_ALLOWED[]="\
<!DOCTYPE html> \
-<html><title>Method NOT allowe</title><body><center> \
+<html><title>Method NOT allowed</title><body><center> \
<h3>ONLY POSTs are allowed.</h3> \
</center></body></html>";
static char page_MHD_HTTP_INTERNAL_SERVER_ERROR[]="\
@@ -316,153 +325,122 @@ url_handler (void *cls,
printf ("%s\n", url);
unsigned int status;
unsigned int no_destroy;
- json_int_t prod_id;
- json_int_t contract_id;
- struct Contract *contract;
- void *contract_and_desc;
struct GNUNET_CRYPTO_EddsaSignature c_sig;
- struct MHD_Response *resp;
- struct TALER_Amount price;
struct GNUNET_CRYPTO_EddsaPublicKey pub;
- json_t *json_price;
+ struct ContractNBO contract;
+ struct MHD_Response *resp;
+ json_t *j_contract_complete;
json_t *root;
- json_t *contract_enc;
- json_t *sig_enc;
+ json_t *j_sig_enc;
json_t *eddsa_pub_enc;
json_t *response;
int res = GNUNET_SYSERR;
- const char *desc;
#define URL_HELLO "/hello"
#define URL_CONTRACT "/contract"
no_destroy = 0;
resp = NULL;
- contract = NULL;
status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+
if (0 == strncasecmp (url, URL_HELLO, sizeof (URL_HELLO)))
+ {
+ if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
+ status = generate_hello (&resp);
+ else
{
- if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
- status = generate_hello (&resp);
- else
- GNUNET_break (0);
+ status = MHD_HTTP_METHOD_NOT_ALLOWED;
}
+ }
+
+ /*
+ * To be called by the frontend passing the contract with some "holes"
+ * which will be completed, stored in DB, signed, and returned
+ *
+ */
- // to be called by the frontend passing all the product's information
- // which are relevant for the contract's generation
if (0 == strncasecmp (url, URL_CONTRACT, sizeof (URL_CONTRACT)))
{
if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
{
status = MHD_HTTP_METHOD_NOT_ALLOWED;
+ goto end;
}
else
res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &root);
-
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &root);
if (GNUNET_SYSERR == res)
- status = MHD_HTTP_METHOD_NOT_ALLOWED;
+ {
+ status = MHD_HTTP_BAD_REQUEST;
+ goto end;
+ }
/* the POST's body has to be fetched furthermore */
if ((GNUNET_NO == res) || (NULL == root))
return MHD_YES;
- /* The frontend should supply a JSON in the follwoing format:
+ /* The frontend should supply a JSON in the format described in
+ http://link-to-specs : */
+ if (NULL == (j_contract_complete = MERCHANT_handle_contract (root,
+ db_conn,
+ wire,
+ &contract)))
{
-
- "desc" : string human-readable describing this deal,
- "product" : uint64-like integer referring to the product in some
- DB adminstered by the frontend,
- "cid" : uint64-like integer, this contract's id
- "price" : a 'struct TALER_Amount' in the Taler compliant JSON format }
-
- */
-
- if ((res = json_unpack (root, "{s:s, s:I, s:I, s:o}",
- "desc",
- &desc,
- "product",
- &prod_id,
- "cid",
- &contract_id,
- "price",
- &json_price
- )))
- /* still not possible to return a taler-compliant error message
- since this JSON format is not among the taler officials ones */
- status = MHD_HTTP_BAD_REQUEST;
- else
- {
+ status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ goto end;
+ }
- if (GNUNET_OK != TALER_json_to_amount (json_price, &price))
- /* still not possible to return a taler-compliant error message
- since this JSON format is not among the taler officials ones */
- status = MHD_HTTP_BAD_REQUEST;
- else
- {
- /* Let's generate this contract! */
- /* FIXME : change this. Not existent anymore */
- if (NULL == (contract_and_desc = generate_and_store_contract (desc,
- contract_id,
- prod_id,
- &price,
- &c_sig)))
- {
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- }
- else
- {
- json_decref (root);
- json_decref (json_price);
- contract = (struct Contract *) contract_and_desc;
-
- /* the contract is good and stored in DB, produce now JSON to return.
- As of now, the format is {"contract" : base32contract,
- "sig" : contractSignature,
- "eddsa_pub" : keyToCheckSignatureAgainst
- }
-
- */
+ GNUNET_CRYPTO_eddsa_sign (privkey, &contract.purpose, &c_sig);
+
+ /**
+ *
+ * As of now, the format is
+ *
+ * {"contract" : {the contract in "plain" JSON},
+ * "sig" : base32 encoding of the signed 'struct ContractNBO',
+ * "eddsa_pub" : base32 encoding of merchant's public key}
+ *
+ */
- sig_enc = TALER_json_from_eddsa_sig (&contract->purpose, &c_sig);
- GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pub);
- eddsa_pub_enc = TALER_json_from_data ((void *) &pub, sizeof (pub));
- contract_enc = TALER_json_from_data ((void *) contract,
- sizeof (*contract) + strlen (desc) + 1);
- GNUNET_free (contract_and_desc);
-
- response = json_pack ("{s:o, s:o, s:o}",
- "contract", contract_enc,
- "sig", sig_enc,
- "eddsa_pub", eddsa_pub_enc);
-
- TMH_RESPONSE_reply_json (connection, response, MHD_HTTP_OK);
- return MHD_YES;
-
- }
- }
- }
+ j_sig_enc = TALER_json_from_eddsa_sig (&contract.purpose, &c_sig);
+ GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pub);
+ eddsa_pub_enc = TALER_json_from_data ((void *) &pub, sizeof (pub));
+ response = json_pack ("{s:o, s:o, s:o}",
+ "contract", j_contract_complete,
+ "sig", j_sig_enc,
+ "eddsa_pub", eddsa_pub_enc);
+
+ TMH_RESPONSE_reply_json (connection, response, MHD_HTTP_OK);
+ return MHD_YES;
+
}
+ end:
+
if (NULL != resp)
- {
- EXITIF (MHD_YES != MHD_queue_response (connection, status, resp));
- if (!no_destroy)
- MHD_destroy_response (resp);
- }
+ {
+ EXITIF (MHD_YES != MHD_queue_response (connection, status, resp));
+ return MHD_YES;
+ if (!no_destroy)
+ MHD_destroy_response (resp);
+ }
else
+ {
+
EXITIF (GNUNET_OK != failure_resp (connection, status));
- return MHD_YES;
+ return MHD_YES;
- EXITIF_exit:
- result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_shutdown ();
- return MHD_NO;
+ }
+
+ EXITIF_exit:
+ result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_shutdown ();
+ return MHD_NO;
}
/**
@@ -527,7 +505,6 @@ run (void *cls, char *const *args, const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *config)
{
- char *keyfile;
unsigned int nmints;
unsigned int cnt;
struct MERCHANT_MintInfo *mint_infos;
@@ -541,7 +518,7 @@ run (void *cls, char *const *args, const char *cfgfile,
&do_shutdown, NULL);
EXITIF (GNUNET_SYSERR == (nmints = TALER_MERCHANT_parse_mints (config,
&mint_infos)));
-
+ EXITIF (NULL == (wire = TALER_MERCHANT_parse_wireformat_sepa (config)));
EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (config,
"merchant",
"KEYFILE",
diff --git a/src/tests/merchant-contract-test b/src/tests/merchant-contract-test
Binary files differ.
diff --git a/src/tests/merchant-contract-test.c b/src/tests/merchant-contract-test.c
@@ -93,7 +93,7 @@ run (void *cls, char *const *args, const char *cfgfile,
struct TALER_Amount amount;
int64_t t_id;
int64_t p_id;
- struct GNUNET_CRYPTO_EddsaSignature c_sig;
+ struct ContractNBO contract;
struct GNUNET_TIME_Absolute deldate;
db_conn = NULL;
@@ -249,9 +249,8 @@ run (void *cls, char *const *args, const char *cfgfile,
j_root = MERCHANT_handle_contract (j_fake_contract,
db_conn,
- privkey,
wire,
- &c_sig);
+ &contract);
#if 1
str = json_dumps (j_root, JSON_INDENT(2) | JSON_PRESERVE_ORDER);