make TALER_MINT_parse_json_data more expressive, add RSA types as well
This commit is contained in:
parent
a284561298
commit
4a27969e5e
@ -127,8 +127,8 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
|
|||||||
char *wire_enc;
|
char *wire_enc;
|
||||||
size_t len;
|
size_t len;
|
||||||
struct GNUNET_MINT_ParseFieldSpec spec[] = {
|
struct GNUNET_MINT_ParseFieldSpec spec[] = {
|
||||||
TALER_MINT_PARSE_VARIABLE ("denom_pub"),
|
TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &deposit.coin.denom_pub),
|
||||||
TALER_MINT_PARSE_VARIABLE ("ubsig"),
|
TALER_MINT_PARSE_RSA_SIGNATURE ("ubsig", &deposit.coin.denom_sig),
|
||||||
TALER_MINT_PARSE_FIXED ("coin_pub", &deposit.coin.coin_pub),
|
TALER_MINT_PARSE_FIXED ("coin_pub", &deposit.coin.coin_pub),
|
||||||
TALER_MINT_PARSE_FIXED ("merchant_pub", &deposit.merchant_pub),
|
TALER_MINT_PARSE_FIXED ("merchant_pub", &deposit.merchant_pub),
|
||||||
TALER_MINT_PARSE_FIXED ("H_a", &deposit.h_contract),
|
TALER_MINT_PARSE_FIXED ("H_a", &deposit.h_contract),
|
||||||
@ -146,32 +146,9 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
|
|||||||
return MHD_NO; /* hard failure */
|
return MHD_NO; /* hard failure */
|
||||||
if (GNUNET_NO == res)
|
if (GNUNET_NO == res)
|
||||||
return MHD_YES; /* failure */
|
return MHD_YES; /* failure */
|
||||||
deposit.coin.denom_pub
|
|
||||||
= GNUNET_CRYPTO_rsa_public_key_decode (spec[0].destination,
|
|
||||||
spec[0].destination_size_out);
|
|
||||||
if (NULL == deposit.coin.denom_pub)
|
|
||||||
{
|
|
||||||
LOG_WARNING ("Failed to parse denomination key for /deposit request\n");
|
|
||||||
TALER_MINT_release_parsed_data (spec);
|
|
||||||
return TALER_MINT_reply_arg_invalid (connection,
|
|
||||||
"denom_pub");
|
|
||||||
}
|
|
||||||
deposit.coin.denom_sig
|
|
||||||
= GNUNET_CRYPTO_rsa_signature_decode (spec[1].destination,
|
|
||||||
spec[1].destination_size_out);
|
|
||||||
if (NULL == deposit.coin.denom_sig)
|
|
||||||
{
|
|
||||||
LOG_WARNING ("Failed to parse unblinded signature for /deposit request\n");
|
|
||||||
GNUNET_CRYPTO_rsa_public_key_free (deposit.coin.denom_pub);
|
|
||||||
TALER_MINT_release_parsed_data (spec);
|
|
||||||
return TALER_MINT_reply_arg_invalid (connection,
|
|
||||||
"denom_pub");
|
|
||||||
}
|
|
||||||
/* FIXME: check that "wire" is formatted correctly */
|
/* FIXME: check that "wire" is formatted correctly */
|
||||||
if (NULL == (wire_enc = json_dumps (wire, JSON_COMPACT | JSON_SORT_KEYS)))
|
if (NULL == (wire_enc = json_dumps (wire, JSON_COMPACT | JSON_SORT_KEYS)))
|
||||||
{
|
{
|
||||||
GNUNET_CRYPTO_rsa_public_key_free (deposit.coin.denom_pub);
|
|
||||||
GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig);
|
|
||||||
LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
|
LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
|
||||||
TALER_MINT_release_parsed_data (spec);
|
TALER_MINT_release_parsed_data (spec);
|
||||||
return TALER_MINT_reply_arg_invalid (connection,
|
return TALER_MINT_reply_arg_invalid (connection,
|
||||||
@ -187,8 +164,6 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
|
|||||||
deposit.amount = *amount;
|
deposit.amount = *amount;
|
||||||
res = verify_and_execute_deposit (connection,
|
res = verify_and_execute_deposit (connection,
|
||||||
&deposit);
|
&deposit);
|
||||||
GNUNET_CRYPTO_rsa_public_key_free (deposit.coin.denom_pub);
|
|
||||||
GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig);
|
|
||||||
TALER_MINT_release_parsed_data (spec);
|
TALER_MINT_release_parsed_data (spec);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -260,402 +260,6 @@ TALER_MINT_parse_post_cleanup_callback (void *con_cls)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigate through a JSON tree.
|
|
||||||
*
|
|
||||||
* Sends an error response if navigation is impossible (i.e.
|
|
||||||
* the JSON object is invalid)
|
|
||||||
*
|
|
||||||
* @param connection the connection to send an error response to
|
|
||||||
* @param root the JSON node to start the navigation at.
|
|
||||||
* @param ... navigation specification (see `enum TALER_MINT_JsonNavigationCommand`)
|
|
||||||
* @return
|
|
||||||
* #GNUNET_YES if navigation was successful
|
|
||||||
* #GNUNET_NO if json is malformed, error response was generated
|
|
||||||
* #GNUNET_SYSERR on internal error (no response was generated,
|
|
||||||
* connection must be closed)
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
GNUNET_MINT_parse_navigate_json (struct MHD_Connection *connection,
|
|
||||||
const json_t *root,
|
|
||||||
...)
|
|
||||||
{
|
|
||||||
va_list argp;
|
|
||||||
int ret;
|
|
||||||
json_t *path; /* what's our current path from 'root'? */
|
|
||||||
|
|
||||||
path = json_array ();
|
|
||||||
va_start (argp, root);
|
|
||||||
ret = 2; /* just not any of the valid return values */
|
|
||||||
while (2 == ret)
|
|
||||||
{
|
|
||||||
enum TALER_MINT_JsonNavigationCommand command
|
|
||||||
= va_arg (argp,
|
|
||||||
enum TALER_MINT_JsonNavigationCommand);
|
|
||||||
|
|
||||||
switch (command)
|
|
||||||
{
|
|
||||||
case JNAV_FIELD:
|
|
||||||
{
|
|
||||||
const char *fname = va_arg(argp, const char *);
|
|
||||||
|
|
||||||
json_array_append_new (path,
|
|
||||||
json_string (fname));
|
|
||||||
root = json_object_get (root,
|
|
||||||
fname);
|
|
||||||
if (NULL == root)
|
|
||||||
{
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s, s:s, s:o}",
|
|
||||||
"error",
|
|
||||||
"missing field in JSON",
|
|
||||||
"field",
|
|
||||||
fname,
|
|
||||||
"path",
|
|
||||||
path))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JNAV_INDEX:
|
|
||||||
{
|
|
||||||
int fnum = va_arg(argp, int);
|
|
||||||
|
|
||||||
json_array_append_new (path,
|
|
||||||
json_integer (fnum));
|
|
||||||
root = json_array_get (root,
|
|
||||||
fnum);
|
|
||||||
if (NULL == root)
|
|
||||||
{
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s, s:o}",
|
|
||||||
"error",
|
|
||||||
"missing index in JSON",
|
|
||||||
"path", path))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JNAV_RET_DATA:
|
|
||||||
{
|
|
||||||
void *where = va_arg (argp, void *);
|
|
||||||
size_t len = va_arg (argp, size_t);
|
|
||||||
const char *str;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
str = json_string_value (root);
|
|
||||||
if (NULL == str)
|
|
||||||
{
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s, s:o}",
|
|
||||||
"error",
|
|
||||||
"string expected",
|
|
||||||
"path",
|
|
||||||
path))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
res = GNUNET_STRINGS_string_to_data (str, strlen (str),
|
|
||||||
where, len);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s, s:o}",
|
|
||||||
"error",
|
|
||||||
"malformed binary data in JSON",
|
|
||||||
"path",
|
|
||||||
path))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ret = GNUNET_OK;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JNAV_RET_DATA_VAR:
|
|
||||||
{
|
|
||||||
void **where = va_arg (argp, void **);
|
|
||||||
size_t *len = va_arg (argp, size_t *);
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
str = json_string_value (root);
|
|
||||||
if (NULL == str)
|
|
||||||
{
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_internal_error (connection,
|
|
||||||
"json_string_value() failed"))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*len = (strlen (str) * 5) / 8;
|
|
||||||
if (NULL != where)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
*where = GNUNET_malloc (*len);
|
|
||||||
res = GNUNET_STRINGS_string_to_data (str,
|
|
||||||
strlen (str),
|
|
||||||
*where,
|
|
||||||
*len);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_free (*where);
|
|
||||||
*where = NULL;
|
|
||||||
*len = 0;
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s, s:o}",
|
|
||||||
"error",
|
|
||||||
"malformed binary data in JSON",
|
|
||||||
"path", path))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = GNUNET_OK;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JNAV_RET_TYPED_JSON:
|
|
||||||
{
|
|
||||||
int typ = va_arg (argp, int);
|
|
||||||
const json_t **r_json = va_arg (argp, const json_t **);
|
|
||||||
|
|
||||||
if ( (-1 != typ) && (json_typeof (root) != typ))
|
|
||||||
{
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s, s:i, s:i, s:o}",
|
|
||||||
"error", "wrong JSON field type",
|
|
||||||
"type_expected", typ,
|
|
||||||
"type_actual", json_typeof (root),
|
|
||||||
"path", path))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*r_json = root;
|
|
||||||
ret = GNUNET_OK;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GNUNET_break (0);
|
|
||||||
ret = (MHD_YES ==
|
|
||||||
TALER_MINT_reply_internal_error (connection,
|
|
||||||
"unhandled value in switch"))
|
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
va_end (argp);
|
|
||||||
json_decref (path);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse JSON object into components based on the given field
|
|
||||||
* specification.
|
|
||||||
*
|
|
||||||
* @param connection the connection to send an error response to
|
|
||||||
* @param root the JSON node to start the navigation at.
|
|
||||||
* @param spec field specification for the parser
|
|
||||||
* @return
|
|
||||||
* #GNUNET_YES if navigation was successful (caller is responsible
|
|
||||||
* for freeing allocated variable-size data using
|
|
||||||
* #TALER_MINT_release_parsed_data() when done)
|
|
||||||
* #GNUNET_NO if json is malformed, error response was generated
|
|
||||||
* #GNUNET_SYSERR on internal error
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
TALER_MINT_parse_json_data (struct MHD_Connection *connection,
|
|
||||||
const json_t *root,
|
|
||||||
struct GNUNET_MINT_ParseFieldSpec *spec)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
int ret;
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
ret = GNUNET_YES;
|
|
||||||
for (i=0; NULL != spec[i].field_name; i++)
|
|
||||||
{
|
|
||||||
switch (spec[i].command)
|
|
||||||
{
|
|
||||||
case JNAV_FIELD:
|
|
||||||
GNUNET_break (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
case JNAV_INDEX:
|
|
||||||
GNUNET_break (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
case JNAV_RET_DATA:
|
|
||||||
if (GNUNET_YES != ret)
|
|
||||||
break;
|
|
||||||
ret = GNUNET_MINT_parse_navigate_json (connection,
|
|
||||||
root,
|
|
||||||
JNAV_FIELD,
|
|
||||||
spec[i].field_name,
|
|
||||||
JNAV_RET_DATA,
|
|
||||||
spec[i].destination,
|
|
||||||
spec[i].destination_size_in);
|
|
||||||
break;
|
|
||||||
case JNAV_RET_DATA_VAR:
|
|
||||||
if (GNUNET_YES != ret)
|
|
||||||
break;
|
|
||||||
ptr = NULL;
|
|
||||||
ret = GNUNET_MINT_parse_navigate_json (connection,
|
|
||||||
root,
|
|
||||||
JNAV_FIELD,
|
|
||||||
spec[i].field_name,
|
|
||||||
JNAV_RET_DATA_VAR,
|
|
||||||
&ptr,
|
|
||||||
&spec[i].destination_size_out);
|
|
||||||
spec[i].destination = ptr;
|
|
||||||
break;
|
|
||||||
case JNAV_RET_TYPED_JSON:
|
|
||||||
if (GNUNET_YES != ret)
|
|
||||||
break;
|
|
||||||
ptr = NULL;
|
|
||||||
ret = GNUNET_MINT_parse_navigate_json (connection,
|
|
||||||
root,
|
|
||||||
JNAV_FIELD,
|
|
||||||
spec[i].field_name,
|
|
||||||
JNAV_RET_TYPED_JSON,
|
|
||||||
spec[i].type,
|
|
||||||
&ptr);
|
|
||||||
spec[i].destination = ptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (GNUNET_YES != ret)
|
|
||||||
TALER_MINT_release_parsed_data (spec);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release all memory allocated for the variable-size fields in
|
|
||||||
* the parser specification.
|
|
||||||
*
|
|
||||||
* @param spec specification to free
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i=0; NULL != spec[i].field_name; i++)
|
|
||||||
{
|
|
||||||
switch (spec[i].command)
|
|
||||||
{
|
|
||||||
case JNAV_FIELD:
|
|
||||||
GNUNET_break (0);
|
|
||||||
return;
|
|
||||||
case JNAV_INDEX:
|
|
||||||
GNUNET_break (0);
|
|
||||||
return;
|
|
||||||
case JNAV_RET_DATA:
|
|
||||||
break;
|
|
||||||
case JNAV_RET_DATA_VAR:
|
|
||||||
if (0 != spec[i].destination_size_out)
|
|
||||||
{
|
|
||||||
GNUNET_free (spec[i].destination);
|
|
||||||
spec[i].destination = NULL;
|
|
||||||
spec[i].destination_size_out = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JNAV_RET_TYPED_JSON:
|
|
||||||
if (NULL != spec[i].destination)
|
|
||||||
{
|
|
||||||
json_decref (spec[i].destination);
|
|
||||||
spec[i].destination = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse amount specified in JSON format.
|
|
||||||
*
|
|
||||||
* @param connection the MHD connection (to report errors)
|
|
||||||
* @param f json specification of the amount
|
|
||||||
* @param amount[OUT] set to the amount specified in @a f
|
|
||||||
* @return
|
|
||||||
* #GNUNET_YES if parsing was successful
|
|
||||||
* #GNUNET_NO if json is malformed, error response was generated
|
|
||||||
* #GNUNET_SYSERR on internal error, error response was not generated
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
|
|
||||||
json_t *f,
|
|
||||||
struct TALER_Amount *amount)
|
|
||||||
{
|
|
||||||
json_int_t value;
|
|
||||||
json_int_t fraction;
|
|
||||||
const char *currency;
|
|
||||||
struct TALER_Amount a;
|
|
||||||
|
|
||||||
if (-1 == json_unpack (f,
|
|
||||||
"{s:I, s:I, s:s}",
|
|
||||||
"value", &value,
|
|
||||||
"fraction", &fraction,
|
|
||||||
"currency", ¤cy))
|
|
||||||
{
|
|
||||||
LOG_WARNING ("Failed to parse JSON amount specification\n");
|
|
||||||
if (MHD_YES !=
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s}",
|
|
||||||
"error", "Bad format"))
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
if ( (value < 0) ||
|
|
||||||
(fraction < 0) ||
|
|
||||||
(value > UINT32_MAX) ||
|
|
||||||
(fraction > UINT32_MAX) )
|
|
||||||
{
|
|
||||||
LOG_WARNING ("Amount specified not in allowed range\n");
|
|
||||||
if (MHD_YES !=
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s}",
|
|
||||||
"error", "Amount outside of allowed range"))
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
if (0 != strcmp (currency,
|
|
||||||
MINT_CURRENCY))
|
|
||||||
{
|
|
||||||
LOG_WARNING ("Currency specified not supported by this mint\n");
|
|
||||||
if (MHD_YES !=
|
|
||||||
TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s, s:s}",
|
|
||||||
"error", "Currency not supported",
|
|
||||||
"currency", currency))
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
a.value = (uint32_t) value;
|
|
||||||
a.fraction = (uint32_t) fraction;
|
|
||||||
GNUNET_assert (strlen (MINT_CURRENCY) < TALER_CURRENCY_LEN);
|
|
||||||
strcpy (a.currency, MINT_CURRENCY);
|
|
||||||
*amount = TALER_amount_normalize (a);
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract base32crockford encoded data from request.
|
* Extract base32crockford encoded data from request.
|
||||||
*
|
*
|
||||||
@ -756,5 +360,576 @@ TALER_MINT_mhd_request_var_arg_data (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate through a JSON tree.
|
||||||
|
*
|
||||||
|
* Sends an error response if navigation is impossible (i.e.
|
||||||
|
* the JSON object is invalid)
|
||||||
|
*
|
||||||
|
* @param connection the connection to send an error response to
|
||||||
|
* @param root the JSON node to start the navigation at.
|
||||||
|
* @param ... navigation specification (see `enum TALER_MINT_JsonNavigationCommand`)
|
||||||
|
* @return
|
||||||
|
* #GNUNET_YES if navigation was successful
|
||||||
|
* #GNUNET_NO if json is malformed, error response was generated
|
||||||
|
* #GNUNET_SYSERR on internal error (no response was generated,
|
||||||
|
* connection must be closed)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
GNUNET_MINT_parse_navigate_json (struct MHD_Connection *connection,
|
||||||
|
const json_t *root,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list argp;
|
||||||
|
int ret;
|
||||||
|
json_t *path; /* what's our current path from 'root'? */
|
||||||
|
|
||||||
|
path = json_array ();
|
||||||
|
va_start (argp, root);
|
||||||
|
ret = 2; /* just not any of the valid return values */
|
||||||
|
while (2 == ret)
|
||||||
|
{
|
||||||
|
enum TALER_MINT_JsonNavigationCommand command
|
||||||
|
= va_arg (argp,
|
||||||
|
enum TALER_MINT_JsonNavigationCommand);
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case JNAV_FIELD:
|
||||||
|
{
|
||||||
|
const char *fname = va_arg(argp, const char *);
|
||||||
|
|
||||||
|
json_array_append_new (path,
|
||||||
|
json_string (fname));
|
||||||
|
root = json_object_get (root,
|
||||||
|
fname);
|
||||||
|
if (NULL == root)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"missing field in JSON",
|
||||||
|
"field",
|
||||||
|
fname,
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JNAV_INDEX:
|
||||||
|
{
|
||||||
|
int fnum = va_arg(argp, int);
|
||||||
|
|
||||||
|
json_array_append_new (path,
|
||||||
|
json_integer (fnum));
|
||||||
|
root = json_array_get (root,
|
||||||
|
fnum);
|
||||||
|
if (NULL == root)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"missing index in JSON",
|
||||||
|
"path", path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JNAV_RET_DATA:
|
||||||
|
{
|
||||||
|
void *where = va_arg (argp, void *);
|
||||||
|
size_t len = va_arg (argp, size_t);
|
||||||
|
const char *str;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
// FIXME: avoidable code duplication here...
|
||||||
|
str = json_string_value (root);
|
||||||
|
if (NULL == str)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"string expected",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res = GNUNET_STRINGS_string_to_data (str, strlen (str),
|
||||||
|
where, len);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"malformed binary data in JSON",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = GNUNET_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JNAV_RET_DATA_VAR:
|
||||||
|
{
|
||||||
|
void **where = va_arg (argp, void **);
|
||||||
|
size_t *len = va_arg (argp, size_t *);
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
// FIXME: avoidable code duplication here...
|
||||||
|
str = json_string_value (root);
|
||||||
|
if (NULL == str)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_internal_error (connection,
|
||||||
|
"json_string_value() failed"))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*len = (strlen (str) * 5) / 8;
|
||||||
|
if (NULL != where)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
*where = GNUNET_malloc (*len);
|
||||||
|
res = GNUNET_STRINGS_string_to_data (str,
|
||||||
|
strlen (str),
|
||||||
|
*where,
|
||||||
|
*len);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_free (*where);
|
||||||
|
*where = NULL;
|
||||||
|
*len = 0;
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"malformed binary data in JSON",
|
||||||
|
"path", path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = GNUNET_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JNAV_RET_TYPED_JSON:
|
||||||
|
{
|
||||||
|
int typ = va_arg (argp, int);
|
||||||
|
const json_t **r_json = va_arg (argp, const json_t **);
|
||||||
|
|
||||||
|
if ( (-1 != typ) && (json_typeof (root) != typ))
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:i, s:i, s:o}",
|
||||||
|
"error", "wrong JSON field type",
|
||||||
|
"type_expected", typ,
|
||||||
|
"type_actual", json_typeof (root),
|
||||||
|
"path", path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*r_json = root;
|
||||||
|
ret = GNUNET_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JNAV_RET_RSA_PUBLIC_KEY:
|
||||||
|
{
|
||||||
|
void **where = va_arg (argp, void **);
|
||||||
|
size_t len;
|
||||||
|
const char *str;
|
||||||
|
int res;
|
||||||
|
void *buf;
|
||||||
|
|
||||||
|
// FIXME: avoidable code duplication here...
|
||||||
|
str = json_string_value (root);
|
||||||
|
if (NULL == str)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"string expected",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = (strlen (str) * 5) / 8;
|
||||||
|
buf = GNUNET_malloc (len);
|
||||||
|
res = GNUNET_STRINGS_string_to_data (str,
|
||||||
|
strlen (str),
|
||||||
|
buf,
|
||||||
|
len);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_free (buf);
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"malformed binary data in JSON",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*where = GNUNET_CRYPTO_rsa_public_key_decode (buf,
|
||||||
|
len);
|
||||||
|
GNUNET_free (buf);
|
||||||
|
if (NULL == *where)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"malformed RSA public key in JSON",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = GNUNET_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case JNAV_RET_RSA_SIGNATURE:
|
||||||
|
{
|
||||||
|
void **where = va_arg (argp, void **);
|
||||||
|
size_t len;
|
||||||
|
const char *str;
|
||||||
|
int res;
|
||||||
|
void *buf;
|
||||||
|
|
||||||
|
// FIXME: avoidable code duplication here...
|
||||||
|
str = json_string_value (root);
|
||||||
|
if (NULL == str)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"string expected",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = (strlen (str) * 5) / 8;
|
||||||
|
buf = GNUNET_malloc (len);
|
||||||
|
res = GNUNET_STRINGS_string_to_data (str,
|
||||||
|
strlen (str),
|
||||||
|
buf,
|
||||||
|
len);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_free (buf);
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"malformed binary data in JSON",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*where = GNUNET_CRYPTO_rsa_signature_decode (buf,
|
||||||
|
len);
|
||||||
|
GNUNET_free (buf);
|
||||||
|
if (NULL == *where)
|
||||||
|
{
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:o}",
|
||||||
|
"error",
|
||||||
|
"malformed RSA signature in JSON",
|
||||||
|
"path",
|
||||||
|
path))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = GNUNET_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
GNUNET_break (0);
|
||||||
|
ret = (MHD_YES ==
|
||||||
|
TALER_MINT_reply_internal_error (connection,
|
||||||
|
"unhandled value in switch"))
|
||||||
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end (argp);
|
||||||
|
json_decref (path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse JSON object into components based on the given field
|
||||||
|
* specification.
|
||||||
|
*
|
||||||
|
* @param connection the connection to send an error response to
|
||||||
|
* @param root the JSON node to start the navigation at.
|
||||||
|
* @param spec field specification for the parser
|
||||||
|
* @return
|
||||||
|
* #GNUNET_YES if navigation was successful (caller is responsible
|
||||||
|
* for freeing allocated variable-size data using
|
||||||
|
* #TALER_MINT_release_parsed_data() when done)
|
||||||
|
* #GNUNET_NO if json is malformed, error response was generated
|
||||||
|
* #GNUNET_SYSERR on internal error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_parse_json_data (struct MHD_Connection *connection,
|
||||||
|
const json_t *root,
|
||||||
|
struct GNUNET_MINT_ParseFieldSpec *spec)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
int ret;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ret = GNUNET_YES;
|
||||||
|
for (i=0; NULL != spec[i].field_name; i++)
|
||||||
|
{
|
||||||
|
switch (spec[i].command)
|
||||||
|
{
|
||||||
|
case JNAV_FIELD:
|
||||||
|
GNUNET_break (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
case JNAV_INDEX:
|
||||||
|
GNUNET_break (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
case JNAV_RET_DATA:
|
||||||
|
if (GNUNET_YES != ret)
|
||||||
|
break;
|
||||||
|
ret = GNUNET_MINT_parse_navigate_json (connection,
|
||||||
|
root,
|
||||||
|
JNAV_FIELD,
|
||||||
|
spec[i].field_name,
|
||||||
|
JNAV_RET_DATA,
|
||||||
|
spec[i].destination,
|
||||||
|
spec[i].destination_size_in);
|
||||||
|
break;
|
||||||
|
case JNAV_RET_DATA_VAR:
|
||||||
|
if (GNUNET_YES != ret)
|
||||||
|
break;
|
||||||
|
ptr = NULL;
|
||||||
|
ret = GNUNET_MINT_parse_navigate_json (connection,
|
||||||
|
root,
|
||||||
|
JNAV_FIELD,
|
||||||
|
spec[i].field_name,
|
||||||
|
JNAV_RET_DATA_VAR,
|
||||||
|
&ptr,
|
||||||
|
&spec[i].destination_size_out);
|
||||||
|
spec[i].destination = ptr;
|
||||||
|
break;
|
||||||
|
case JNAV_RET_TYPED_JSON:
|
||||||
|
if (GNUNET_YES != ret)
|
||||||
|
break;
|
||||||
|
ptr = NULL;
|
||||||
|
ret = GNUNET_MINT_parse_navigate_json (connection,
|
||||||
|
root,
|
||||||
|
JNAV_FIELD,
|
||||||
|
spec[i].field_name,
|
||||||
|
JNAV_RET_TYPED_JSON,
|
||||||
|
spec[i].type,
|
||||||
|
&ptr);
|
||||||
|
*((void**)spec[i].destination) = ptr;
|
||||||
|
break;
|
||||||
|
case JNAV_RET_RSA_PUBLIC_KEY:
|
||||||
|
if (GNUNET_YES != ret)
|
||||||
|
break;
|
||||||
|
ptr = NULL;
|
||||||
|
ret = GNUNET_MINT_parse_navigate_json (connection,
|
||||||
|
root,
|
||||||
|
JNAV_FIELD,
|
||||||
|
spec[i].field_name,
|
||||||
|
JNAV_RET_RSA_PUBLIC_KEY,
|
||||||
|
&ptr);
|
||||||
|
spec[i].destination = ptr;
|
||||||
|
break;
|
||||||
|
case JNAV_RET_RSA_SIGNATURE:
|
||||||
|
if (GNUNET_YES != ret)
|
||||||
|
break;
|
||||||
|
ptr = NULL;
|
||||||
|
ret = GNUNET_MINT_parse_navigate_json (connection,
|
||||||
|
root,
|
||||||
|
JNAV_FIELD,
|
||||||
|
spec[i].field_name,
|
||||||
|
JNAV_RET_RSA_SIGNATURE,
|
||||||
|
&ptr);
|
||||||
|
spec[i].destination = ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GNUNET_YES != ret)
|
||||||
|
TALER_MINT_release_parsed_data (spec);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release all memory allocated for the variable-size fields in
|
||||||
|
* the parser specification.
|
||||||
|
*
|
||||||
|
* @param spec specification to free
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
for (i=0; NULL != spec[i].field_name; i++)
|
||||||
|
{
|
||||||
|
switch (spec[i].command)
|
||||||
|
{
|
||||||
|
case JNAV_FIELD:
|
||||||
|
GNUNET_break (0);
|
||||||
|
return;
|
||||||
|
case JNAV_INDEX:
|
||||||
|
GNUNET_break (0);
|
||||||
|
return;
|
||||||
|
case JNAV_RET_DATA:
|
||||||
|
break;
|
||||||
|
case JNAV_RET_DATA_VAR:
|
||||||
|
if (0 != spec[i].destination_size_out)
|
||||||
|
{
|
||||||
|
GNUNET_free (spec[i].destination);
|
||||||
|
spec[i].destination = NULL;
|
||||||
|
spec[i].destination_size_out = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JNAV_RET_TYPED_JSON:
|
||||||
|
ptr = *(void **) spec[i].destination;
|
||||||
|
if (NULL != ptr)
|
||||||
|
{
|
||||||
|
json_decref (ptr);
|
||||||
|
*(void**) spec[i].destination = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JNAV_RET_RSA_PUBLIC_KEY:
|
||||||
|
ptr = *(void **) spec[i].destination;
|
||||||
|
if (NULL != ptr)
|
||||||
|
{
|
||||||
|
GNUNET_CRYPTO_rsa_public_key_free (ptr);
|
||||||
|
*(void**) spec[i].destination = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JNAV_RET_RSA_SIGNATURE:
|
||||||
|
ptr = *(void **) spec[i].destination;
|
||||||
|
if (NULL != ptr)
|
||||||
|
{
|
||||||
|
GNUNET_CRYPTO_rsa_signature_free (ptr);
|
||||||
|
*(void**) spec[i].destination = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse amount specified in JSON format.
|
||||||
|
*
|
||||||
|
* @param connection the MHD connection (to report errors)
|
||||||
|
* @param f json specification of the amount
|
||||||
|
* @param amount[OUT] set to the amount specified in @a f
|
||||||
|
* @return
|
||||||
|
* #GNUNET_YES if parsing was successful
|
||||||
|
* #GNUNET_NO if json is malformed, error response was generated
|
||||||
|
* #GNUNET_SYSERR on internal error, error response was not generated
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
|
||||||
|
json_t *f,
|
||||||
|
struct TALER_Amount *amount)
|
||||||
|
{
|
||||||
|
json_int_t value;
|
||||||
|
json_int_t fraction;
|
||||||
|
const char *currency;
|
||||||
|
struct TALER_Amount a;
|
||||||
|
|
||||||
|
if (-1 == json_unpack (f,
|
||||||
|
"{s:I, s:I, s:s}",
|
||||||
|
"value", &value,
|
||||||
|
"fraction", &fraction,
|
||||||
|
"currency", ¤cy))
|
||||||
|
{
|
||||||
|
LOG_WARNING ("Failed to parse JSON amount specification\n");
|
||||||
|
if (MHD_YES !=
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s}",
|
||||||
|
"error", "Bad format"))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
if ( (value < 0) ||
|
||||||
|
(fraction < 0) ||
|
||||||
|
(value > UINT32_MAX) ||
|
||||||
|
(fraction > UINT32_MAX) )
|
||||||
|
{
|
||||||
|
LOG_WARNING ("Amount specified not in allowed range\n");
|
||||||
|
if (MHD_YES !=
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s}",
|
||||||
|
"error", "Amount outside of allowed range"))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
if (0 != strcmp (currency,
|
||||||
|
MINT_CURRENCY))
|
||||||
|
{
|
||||||
|
LOG_WARNING ("Currency specified not supported by this mint\n");
|
||||||
|
if (MHD_YES !=
|
||||||
|
TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
"{s:s, s:s}",
|
||||||
|
"error", "Currency not supported",
|
||||||
|
"currency", currency))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
a.value = (uint32_t) value;
|
||||||
|
a.fraction = (uint32_t) fraction;
|
||||||
|
GNUNET_assert (strlen (MINT_CURRENCY) < TALER_CURRENCY_LEN);
|
||||||
|
strcpy (a.currency, MINT_CURRENCY);
|
||||||
|
*amount = TALER_amount_normalize (a);
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* end of taler-mint-httpd_parsing.c */
|
/* end of taler-mint-httpd_parsing.c */
|
||||||
|
@ -108,7 +108,19 @@ enum TALER_MINT_JsonNavigationCommand
|
|||||||
* or -1 for any type).
|
* or -1 for any type).
|
||||||
* Params: (int, json_t **)
|
* Params: (int, json_t **)
|
||||||
*/
|
*/
|
||||||
JNAV_RET_TYPED_JSON
|
JNAV_RET_TYPED_JSON,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a `struct GNUNET_CRYPTO_rsa_PublicKey` which was
|
||||||
|
* encoded as variable-size base32crockford encoded data.
|
||||||
|
*/
|
||||||
|
JNAV_RET_RSA_PUBLIC_KEY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a `struct GNUNET_CRYPTO_rsa_Signature` which was
|
||||||
|
* encoded as variable-size base32crockford encoded data.
|
||||||
|
*/
|
||||||
|
JNAV_RET_RSA_SIGNATURE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -230,15 +242,34 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec);
|
|||||||
* Generate line in parser specification for JSON array value.
|
* Generate line in parser specification for JSON array value.
|
||||||
*
|
*
|
||||||
* @param field name of the field
|
* @param field name of the field
|
||||||
|
* @param ptraddr address of pointer to initialize (a `void **`)
|
||||||
*/
|
*/
|
||||||
#define TALER_MINT_PARSE_ARRAY(field) { field, NULL, 0, 0, JNAV_RET_TYPED_JSON, JSON_ARRAY }
|
#define TALER_MINT_PARSE_ARRAY(field,ptraddr) { field, ptraddr, 0, 0, JNAV_RET_TYPED_JSON, JSON_ARRAY }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate line in parser specification for JSON object value.
|
* Generate line in parser specification for JSON object value.
|
||||||
*
|
*
|
||||||
* @param field name of the field
|
* @param field name of the field
|
||||||
|
* @param ptraddr address of pointer to initialize (a `void **`)
|
||||||
*/
|
*/
|
||||||
#define TALER_MINT_PARSE_OBJECT(field) { field, NULL, 0, 0, JNAV_RET_TYPED_JSON, JSON_OBJECT }
|
#define TALER_MINT_PARSE_OBJECT(field,ptraddr) { field, ptraddr, 0, 0, JNAV_RET_TYPED_JSON, JSON_OBJECT }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate line in parser specification for RSA public key.
|
||||||
|
*
|
||||||
|
* @param field name of the field
|
||||||
|
* @param ptraddr address of `struct GNUNET_CRYPTO_rsa_PublicKey *` initialize
|
||||||
|
*/
|
||||||
|
#define TALER_MINT_PARSE_RSA_PUBLIC_KEY(field,ptrpk) { field, ptrpk, 0, 0, JNAV_RET_RSA_PUBLIC_KEY, 0 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate line in parser specification for RSA public key.
|
||||||
|
*
|
||||||
|
* @param field name of the field
|
||||||
|
* @param ptrsig address of `struct GNUNET_CRYPTO_rsa_Signature *` initialize
|
||||||
|
*/
|
||||||
|
#define TALER_MINT_PARSE_RSA_SIGNATURE(field,ptrsig) { field, ptrsig, 0, 0, JNAV_RET_RSA_SIGNATURE, 0 }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,9 +107,9 @@ request_json_require_coin_public_info (struct MHD_Connection *connection,
|
|||||||
struct GNUNET_CRYPTO_rsa_PublicKey *pk;
|
struct GNUNET_CRYPTO_rsa_PublicKey *pk;
|
||||||
struct GNUNET_MINT_ParseFieldSpec spec[] =
|
struct GNUNET_MINT_ParseFieldSpec spec[] =
|
||||||
{
|
{
|
||||||
TALER_MINT_PARSE_FIXED("coin_pub", &r_public_info->coin_pub),
|
TALER_MINT_PARSE_FIXED ("coin_pub", &r_public_info->coin_pub),
|
||||||
TALER_MINT_PARSE_VARIABLE("denom_sig"),
|
TALER_MINT_PARSE_RSA_SIGNATURE ("denom_sig", &sig),
|
||||||
TALER_MINT_PARSE_VARIABLE("denom_pub"),
|
TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk),
|
||||||
TALER_MINT_PARSE_END
|
TALER_MINT_PARSE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -118,21 +118,7 @@ request_json_require_coin_public_info (struct MHD_Connection *connection,
|
|||||||
spec);
|
spec);
|
||||||
if (GNUNET_OK != ret)
|
if (GNUNET_OK != ret)
|
||||||
return ret;
|
return ret;
|
||||||
sig = GNUNET_CRYPTO_rsa_signature_decode (spec[1].destination,
|
// TALER_MINT_release_parsed_data (spec);
|
||||||
spec[1].destination_size_out);
|
|
||||||
pk = GNUNET_CRYPTO_rsa_public_key_decode (spec[2].destination,
|
|
||||||
spec[2].destination_size_out);
|
|
||||||
TALER_MINT_release_parsed_data (spec);
|
|
||||||
if ( (NULL == pk) ||
|
|
||||||
(NULL == sig) )
|
|
||||||
{
|
|
||||||
if (NULL != sig)
|
|
||||||
GNUNET_CRYPTO_rsa_signature_free (sig);
|
|
||||||
if (NULL != pk)
|
|
||||||
GNUNET_CRYPTO_rsa_public_key_free (pk);
|
|
||||||
// FIXME: send error reply...
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
r_public_info->denom_sig = sig;
|
r_public_info->denom_sig = sig;
|
||||||
r_public_info->denom_pub = pk;
|
r_public_info->denom_pub = pk;
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
@ -152,8 +138,8 @@ request_json_require_coin_public_info (struct MHD_Connection *connection,
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
request_json_check_signature (struct MHD_Connection *connection,
|
request_json_check_signature (struct MHD_Connection *connection,
|
||||||
json_t *root,
|
const json_t *root,
|
||||||
struct GNUNET_CRYPTO_EddsaPublicKey *pub,
|
const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
|
||||||
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
|
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
|
||||||
{
|
{
|
||||||
struct GNUNET_CRYPTO_EddsaSignature signature;
|
struct GNUNET_CRYPTO_EddsaSignature signature;
|
||||||
@ -230,100 +216,38 @@ request_json_check_signature (struct MHD_Connection *connection,
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a "/refresh/melt" request
|
* Handle a "/refresh/melt" request after the first parsing has happened.
|
||||||
|
* We now need to validate the coins being melted and the session signature
|
||||||
|
* and then hand things of to execute the melt operation.
|
||||||
*
|
*
|
||||||
* @param rh context of the handler
|
|
||||||
* @param connection the MHD connection to handle
|
* @param connection the MHD connection to handle
|
||||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
* @param refresh_session_pub public key of the melt operation
|
||||||
* @param upload_data upload data
|
* @param new_denoms array of denomination keys
|
||||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
* @param melt_coins array of coins to melt
|
||||||
|
* @param melt_sig_json signature affirming the melt operation
|
||||||
* @return MHD result code
|
* @return MHD result code
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||||
struct MHD_Connection *connection,
|
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||||
void **connection_cls,
|
const json_t *new_denoms,
|
||||||
const char *upload_data,
|
const json_t *melt_coins,
|
||||||
size_t *upload_data_size)
|
const json_t *melt_sig_json)
|
||||||
{
|
{
|
||||||
json_t *root;
|
|
||||||
struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
|
|
||||||
int res;
|
int res;
|
||||||
json_t *new_denoms;
|
|
||||||
unsigned int num_new_denoms;
|
unsigned int num_new_denoms;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct GNUNET_CRYPTO_rsa_PublicKey **denom_pubs;
|
struct GNUNET_CRYPTO_rsa_PublicKey **denom_pubs;
|
||||||
json_t *melt_coins;
|
|
||||||
struct TALER_CoinPublicInfo *coin_public_infos;
|
struct TALER_CoinPublicInfo *coin_public_infos;
|
||||||
unsigned int coin_count;
|
unsigned int coin_count;
|
||||||
struct GNUNET_HashContext *hash_context;
|
struct GNUNET_HashContext *hash_context;
|
||||||
struct GNUNET_HashCode melt_hash;
|
struct GNUNET_HashCode melt_hash;
|
||||||
struct MintKeyState *key_state;
|
struct MintKeyState *key_state;
|
||||||
struct RefreshMeltSignatureBody body;
|
struct RefreshMeltSignatureBody body;
|
||||||
json_t *melt_sig_json;
|
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
||||||
|
|
||||||
res = TALER_MINT_parse_post_json (connection,
|
|
||||||
connection_cls,
|
|
||||||
upload_data,
|
|
||||||
upload_data_size,
|
|
||||||
&root);
|
|
||||||
if (GNUNET_SYSERR == res)
|
|
||||||
return MHD_NO;
|
|
||||||
if ( (GNUNET_NO == res) || (NULL == root) )
|
|
||||||
return MHD_YES;
|
|
||||||
|
|
||||||
res = GNUNET_MINT_parse_navigate_json (connection,
|
|
||||||
root,
|
|
||||||
JNAV_FIELD,
|
|
||||||
"session_pub",
|
|
||||||
JNAV_RET_DATA,
|
|
||||||
&refresh_session_pub,
|
|
||||||
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
|
|
||||||
if (GNUNET_SYSERR == res)
|
|
||||||
return MHD_NO;
|
|
||||||
if (GNUNET_NO == res)
|
|
||||||
return MHD_YES;
|
|
||||||
res = GNUNET_MINT_parse_navigate_json (connection,
|
|
||||||
root,
|
|
||||||
JNAV_FIELD,
|
|
||||||
"new_denoms",
|
|
||||||
JNAV_RET_TYPED_JSON,
|
|
||||||
JSON_ARRAY,
|
|
||||||
&new_denoms);
|
|
||||||
if (GNUNET_SYSERR == res)
|
|
||||||
return MHD_NO;
|
|
||||||
if (GNUNET_NO == res)
|
|
||||||
return MHD_YES;
|
|
||||||
|
|
||||||
res = GNUNET_MINT_parse_navigate_json (connection,
|
|
||||||
root,
|
|
||||||
JNAV_FIELD,
|
|
||||||
"melt_coins",
|
|
||||||
JNAV_RET_TYPED_JSON,
|
|
||||||
JSON_ARRAY,
|
|
||||||
&melt_coins);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
// FIXME: leaks!
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
melt_sig_json = json_object_get (root,
|
|
||||||
"melt_signature");
|
|
||||||
if (NULL == melt_sig_json)
|
|
||||||
{
|
|
||||||
return TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
"{s:s}",
|
|
||||||
"error",
|
|
||||||
"melt_signature missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
num_new_denoms = json_array_size (new_denoms);
|
num_new_denoms = json_array_size (new_denoms);
|
||||||
|
|
||||||
denom_pubs = GNUNET_malloc (num_new_denoms *
|
denom_pubs = GNUNET_malloc (num_new_denoms *
|
||||||
@ -331,8 +255,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
|||||||
|
|
||||||
for (i=0;i<num_new_denoms;i++)
|
for (i=0;i<num_new_denoms;i++)
|
||||||
{
|
{
|
||||||
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
res = GNUNET_MINT_parse_navigate_json (connection, new_denoms,
|
||||||
JNAV_FIELD, "new_denoms",
|
|
||||||
JNAV_INDEX, (int) i,
|
JNAV_INDEX, (int) i,
|
||||||
JNAV_RET_DATA_VAR,
|
JNAV_RET_DATA_VAR,
|
||||||
&buf,
|
&buf,
|
||||||
@ -380,7 +303,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
|||||||
(res = check_confirm_signature (connection,
|
(res = check_confirm_signature (connection,
|
||||||
json_array_get (melt_coins, i),
|
json_array_get (melt_coins, i),
|
||||||
&coin_public_infos[i].coin_pub,
|
&coin_public_infos[i].coin_pub,
|
||||||
&refresh_session_pub)))
|
refresh_session_pub)))
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_SYSERR != res);
|
GNUNET_break (GNUNET_SYSERR != res);
|
||||||
// FIXME: leaks!
|
// FIXME: leaks!
|
||||||
@ -439,7 +362,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
|||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
(res = request_json_check_signature (connection,
|
(res = request_json_check_signature (connection,
|
||||||
melt_sig_json,
|
melt_sig_json,
|
||||||
&refresh_session_pub,
|
refresh_session_pub,
|
||||||
&body.purpose)))
|
&body.purpose)))
|
||||||
{
|
{
|
||||||
// FIXME: generate proper error reply
|
// FIXME: generate proper error reply
|
||||||
@ -448,7 +371,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
|||||||
|
|
||||||
|
|
||||||
res = TALER_MINT_db_execute_refresh_melt (connection,
|
res = TALER_MINT_db_execute_refresh_melt (connection,
|
||||||
&refresh_session_pub,
|
refresh_session_pub,
|
||||||
num_new_denoms,
|
num_new_denoms,
|
||||||
denom_pubs,
|
denom_pubs,
|
||||||
coin_count,
|
coin_count,
|
||||||
@ -458,6 +381,66 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a "/refresh/melt" request. Parses the request into the JSON
|
||||||
|
* components and then hands things of to #handle_referesh_melt_json()
|
||||||
|
* to validate the melted coins, the signature and execute the melt.
|
||||||
|
*
|
||||||
|
* @param rh context of the handler
|
||||||
|
* @param connection the MHD connection to handle
|
||||||
|
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||||
|
* @param upload_data upload data
|
||||||
|
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||||
|
* @return MHD result code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
||||||
|
struct MHD_Connection *connection,
|
||||||
|
void **connection_cls,
|
||||||
|
const char *upload_data,
|
||||||
|
size_t *upload_data_size)
|
||||||
|
{
|
||||||
|
json_t *root;
|
||||||
|
json_t *new_denoms;
|
||||||
|
json_t *melt_coins;
|
||||||
|
json_t *melt_sig_json;
|
||||||
|
struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
|
||||||
|
int res;
|
||||||
|
struct GNUNET_MINT_ParseFieldSpec spec[] = {
|
||||||
|
TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub),
|
||||||
|
TALER_MINT_PARSE_ARRAY ("new_denoms", &new_denoms),
|
||||||
|
TALER_MINT_PARSE_ARRAY ("melt_coins", &melt_coins),
|
||||||
|
TALER_MINT_PARSE_ARRAY ("melt_signature", &melt_sig_json),
|
||||||
|
TALER_MINT_PARSE_END
|
||||||
|
};
|
||||||
|
|
||||||
|
res = TALER_MINT_parse_post_json (connection,
|
||||||
|
connection_cls,
|
||||||
|
upload_data,
|
||||||
|
upload_data_size,
|
||||||
|
&root);
|
||||||
|
if (GNUNET_SYSERR == res)
|
||||||
|
return MHD_NO;
|
||||||
|
if ( (GNUNET_NO == res) || (NULL == root) )
|
||||||
|
return MHD_YES;
|
||||||
|
|
||||||
|
res = TALER_MINT_parse_json_data (connection,
|
||||||
|
root,
|
||||||
|
spec);
|
||||||
|
if (GNUNET_SYSERR == res)
|
||||||
|
return MHD_NO;
|
||||||
|
if (GNUNET_NO == res)
|
||||||
|
return MHD_YES;
|
||||||
|
res = handle_refresh_melt_json (connection,
|
||||||
|
&refresh_session_pub,
|
||||||
|
new_denoms,
|
||||||
|
melt_coins,
|
||||||
|
melt_sig_json);
|
||||||
|
TALER_MINT_release_parsed_data (spec);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a "/refresh/commit" request
|
* Handle a "/refresh/commit" request
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user