/*
This file is part of TALER
Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
*/
/**
* @file util.c
* @brief Common utility functions
* @author Sree Harsha Totakura
* @author Florian Dold
* @author Benedikt Mueller
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_attributes.h"
#include
#include
const char *
TALER_b2s (const void *buf,
size_t buf_size)
{
static TALER_THREAD_LOCAL char ret[9];
struct GNUNET_HashCode hc;
char *tmp;
GNUNET_CRYPTO_hash (buf,
buf_size,
&hc);
tmp = GNUNET_STRINGS_data_to_string_alloc (&hc,
sizeof (hc));
memcpy (ret,
tmp,
8);
GNUNET_free (tmp);
ret[8] = '\0';
return ret;
}
void
TALER_denom_fee_set_hton (struct TALER_DenomFeeSetNBOP *nbo,
const struct TALER_DenomFeeSet *fees)
{
TALER_amount_hton (&nbo->withdraw,
&fees->withdraw);
TALER_amount_hton (&nbo->deposit,
&fees->deposit);
TALER_amount_hton (&nbo->refresh,
&fees->refresh);
TALER_amount_hton (&nbo->refund,
&fees->refund);
}
void
TALER_denom_fee_set_ntoh (struct TALER_DenomFeeSet *fees,
const struct TALER_DenomFeeSetNBOP *nbo)
{
TALER_amount_ntoh (&fees->withdraw,
&nbo->withdraw);
TALER_amount_ntoh (&fees->deposit,
&nbo->deposit);
TALER_amount_ntoh (&fees->refresh,
&nbo->refresh);
TALER_amount_ntoh (&fees->refund,
&nbo->refund);
}
void
TALER_global_fee_set_hton (struct TALER_GlobalFeeSetNBOP *nbo,
const struct TALER_GlobalFeeSet *fees)
{
TALER_amount_hton (&nbo->history,
&fees->history);
TALER_amount_hton (&nbo->account,
&fees->account);
TALER_amount_hton (&nbo->purse,
&fees->purse);
}
void
TALER_global_fee_set_ntoh (struct TALER_GlobalFeeSet *fees,
const struct TALER_GlobalFeeSetNBOP *nbo)
{
TALER_amount_ntoh (&fees->history,
&nbo->history);
TALER_amount_ntoh (&fees->account,
&nbo->account);
TALER_amount_ntoh (&fees->purse,
&nbo->purse);
}
void
TALER_wire_fee_set_hton (struct TALER_WireFeeSetNBOP *nbo,
const struct TALER_WireFeeSet *fees)
{
TALER_amount_hton (&nbo->wire,
&fees->wire);
TALER_amount_hton (&nbo->closing,
&fees->closing);
}
void
TALER_wire_fee_set_ntoh (struct TALER_WireFeeSet *fees,
const struct TALER_WireFeeSetNBOP *nbo)
{
TALER_amount_ntoh (&fees->wire,
&nbo->wire);
TALER_amount_ntoh (&fees->closing,
&nbo->closing);
}
int
TALER_global_fee_set_cmp (const struct TALER_GlobalFeeSet *f1,
const struct TALER_GlobalFeeSet *f2)
{
int ret;
ret = TALER_amount_cmp (&f1->history,
&f2->history);
if (0 != ret)
return ret;
ret = TALER_amount_cmp (&f1->account,
&f2->account);
if (0 != ret)
return ret;
ret = TALER_amount_cmp (&f1->purse,
&f2->purse);
if (0 != ret)
return ret;
return 0;
}
int
TALER_wire_fee_set_cmp (const struct TALER_WireFeeSet *f1,
const struct TALER_WireFeeSet *f2)
{
int ret;
ret = TALER_amount_cmp (&f1->wire,
&f2->wire);
if (0 != ret)
return ret;
ret = TALER_amount_cmp (&f1->closing,
&f2->closing);
if (0 != ret)
return ret;
return 0;
}
enum GNUNET_GenericReturnValue
TALER_denom_fee_check_currency (
const char *currency,
const struct TALER_DenomFeeSet *fees)
{
if (GNUNET_YES !=
TALER_amount_is_currency (&fees->withdraw,
currency))
{
GNUNET_break (0);
return GNUNET_NO;
}
if (GNUNET_YES !=
TALER_amount_is_currency (&fees->deposit,
currency))
{
GNUNET_break (0);
return GNUNET_NO;
}
if (GNUNET_YES !=
TALER_amount_is_currency (&fees->refresh,
currency))
{
GNUNET_break (0);
return GNUNET_NO;
}
if (GNUNET_YES !=
TALER_amount_is_currency (&fees->refund,
currency))
{
GNUNET_break (0);
return GNUNET_NO;
}
return GNUNET_OK;
}
/**
* Dump character in the low range into @a buf
* following RFC 8785.
*
* @param[in,out] buf buffer to modify
* @param val value to dump
*/
static void
lowdump (struct GNUNET_Buffer *buf,
unsigned char val)
{
char scratch[7];
switch (val)
{
case 0x8:
GNUNET_buffer_write (buf,
"\\b",
2);
break;
case 0x9:
GNUNET_buffer_write (buf,
"\\t",
2);
break;
case 0xA:
GNUNET_buffer_write (buf,
"\\n",
2);
break;
case 0xC:
GNUNET_buffer_write (buf,
"\\f",
2);
break;
case 0xD:
GNUNET_buffer_write (buf,
"\\r",
2);
break;
default:
GNUNET_snprintf (scratch,
sizeof (scratch),
"\\u%04x",
(unsigned int) val);
GNUNET_buffer_write (buf,
scratch,
6);
break;
}
}
/**
* Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2).
*
* @param[in,out] inp pointer to string to re-encode
* @return number of bytes in resulting @a inp
*/
size_t
TALER_rfc8785encode (char **inp)
{
struct GNUNET_Buffer buf = { 0 };
size_t left = strlen (*inp) + 1;
size_t olen;
char *in = *inp;
const char *pos = in;
GNUNET_buffer_prealloc (&buf,
left + 40);
buf.warn_grow = 0; /* disable, + 40 is just a wild guess */
while (1)
{
int mbl = u8_mblen ((unsigned char *) pos,
left);
unsigned char val;
if (0 == mbl)
break;
val = (unsigned char) *pos;
if ( (1 == mbl) &&
(val <= 0x1F) )
{
/* Should not happen, as input is produced by
* JSON stringification */
GNUNET_break (0);
lowdump (&buf,
val);
}
else if ( (1 == mbl) && ('\\' == *pos) )
{
switch (*(pos + 1))
{
case '\\':
mbl = 2;
GNUNET_buffer_write (&buf,
pos,
mbl);
break;
case 'u':
{
unsigned int num;
uint32_t n32;
unsigned char res[8];
size_t rlen;
GNUNET_assert ( (1 ==
sscanf (pos + 2,
"%4x",
&num)) ||
(1 ==
sscanf (pos + 2,
"%4X",
&num)) );
mbl = 6;
n32 = (uint32_t) num;
rlen = sizeof (res);
u32_to_u8 (&n32,
1,
res,
&rlen);
if ( (1 == rlen) &&
(res[0] <= 0x1F) )
{
lowdump (&buf,
res[0]);
}
else
{
GNUNET_buffer_write (&buf,
(const char *) res,
rlen);
}
}
break;
default:
mbl = 2;
GNUNET_buffer_write (&buf,
pos,
mbl);
break;
}
}
else
{
GNUNET_buffer_write (&buf,
pos,
mbl);
}
left -= mbl;
pos += mbl;
}
/* 0-terminate buffer */
GNUNET_buffer_write (&buf,
"",
1);
GNUNET_free (in);
*inp = GNUNET_buffer_reap (&buf,
&olen);
return olen;
}
/**
* Hash normalized @a j JSON object or array and
* store the result in @a hc.
*
* @param j JSON to hash
* @param[out] hc where to write the hash
*/
void
TALER_json_hash (const json_t *j,
struct GNUNET_HashCode *hc)
{
char *cstr;
size_t clen;
cstr = json_dumps (j,
JSON_COMPACT | JSON_SORT_KEYS);
GNUNET_assert (NULL != cstr);
clen = TALER_rfc8785encode (&cstr);
GNUNET_CRYPTO_hash (cstr,
clen,
hc);
GNUNET_free (cstr);
}
#ifdef __APPLE__
char *
strchrnul (const char *s,
int c)
{
char *value;
value = strchr (s,
c);
if (NULL == value)
value = &s[strlen (s)];
return value;
}
#endif
void
TALER_CRYPTO_attributes_to_kyc_prox (
const json_t *attr,
struct GNUNET_ShortHashCode *kyc_prox)
{
const char *name = NULL;
const char *birthdate = NULL;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string (TALER_ATTRIBUTE_FULL_NAME,
&name),
NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string (TALER_ATTRIBUTE_BIRTHDATE,
&birthdate),
NULL),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (attr,
spec,
NULL, NULL))
{
GNUNET_break (0);
memset (kyc_prox,
0,
sizeof (*kyc_prox));
return;
}
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (
kyc_prox,
sizeof (*kyc_prox),
name,
(NULL == name)
? 0
: strlen (name),
birthdate,
(NULL == birthdate)
? 0
: strlen (birthdate),
NULL,
0));
}
/* end of util.c */