util.c (11710B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2023 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file util.c 18 * @brief Common utility functions 19 * @author Sree Harsha Totakura <sreeharsha@totakura.in> 20 * @author Florian Dold 21 * @author Benedikt Mueller 22 * @author Christian Grothoff 23 */ 24 #include "platform.h" 25 #include "taler/taler_util.h" 26 #include <gnunet/gnunet_json_lib.h> 27 #include <unistr.h> 28 29 30 int 31 TALER_strcmp_ct (const char *a, 32 const char *b) 33 { 34 size_t alen = strlen (a); 35 36 if (strlen (b) != alen) 37 return 1; 38 return GNUNET_memcmp_ct_ (a, 39 b, 40 alen); 41 } 42 43 44 const char * 45 TALER_b2s (const void *buf, 46 size_t buf_size) 47 { 48 static TALER_THREAD_LOCAL char ret[9]; 49 struct GNUNET_HashCode hc; 50 char *tmp; 51 52 GNUNET_CRYPTO_hash (buf, 53 buf_size, 54 &hc); 55 tmp = GNUNET_STRINGS_data_to_string_alloc (&hc, 56 sizeof (hc)); 57 GNUNET_memcpy (ret, 58 tmp, 59 8); 60 GNUNET_free (tmp); 61 ret[8] = '\0'; 62 return ret; 63 } 64 65 66 void 67 TALER_denom_fee_set_hton (struct TALER_DenomFeeSetNBOP *nbo, 68 const struct TALER_DenomFeeSet *fees) 69 { 70 TALER_amount_hton (&nbo->withdraw, 71 &fees->withdraw); 72 TALER_amount_hton (&nbo->deposit, 73 &fees->deposit); 74 TALER_amount_hton (&nbo->refresh, 75 &fees->refresh); 76 TALER_amount_hton (&nbo->refund, 77 &fees->refund); 78 } 79 80 81 void 82 TALER_denom_fee_set_ntoh (struct TALER_DenomFeeSet *fees, 83 const struct TALER_DenomFeeSetNBOP *nbo) 84 { 85 TALER_amount_ntoh (&fees->withdraw, 86 &nbo->withdraw); 87 TALER_amount_ntoh (&fees->deposit, 88 &nbo->deposit); 89 TALER_amount_ntoh (&fees->refresh, 90 &nbo->refresh); 91 TALER_amount_ntoh (&fees->refund, 92 &nbo->refund); 93 } 94 95 96 void 97 TALER_global_fee_set_hton (struct TALER_GlobalFeeSetNBOP *nbo, 98 const struct TALER_GlobalFeeSet *fees) 99 { 100 TALER_amount_hton (&nbo->history, 101 &fees->history); 102 TALER_amount_hton (&nbo->account, 103 &fees->account); 104 TALER_amount_hton (&nbo->purse, 105 &fees->purse); 106 } 107 108 109 void 110 TALER_global_fee_set_ntoh (struct TALER_GlobalFeeSet *fees, 111 const struct TALER_GlobalFeeSetNBOP *nbo) 112 { 113 TALER_amount_ntoh (&fees->history, 114 &nbo->history); 115 TALER_amount_ntoh (&fees->account, 116 &nbo->account); 117 TALER_amount_ntoh (&fees->purse, 118 &nbo->purse); 119 } 120 121 122 void 123 TALER_wire_fee_set_hton (struct TALER_WireFeeSetNBOP *nbo, 124 const struct TALER_WireFeeSet *fees) 125 { 126 TALER_amount_hton (&nbo->wire, 127 &fees->wire); 128 TALER_amount_hton (&nbo->closing, 129 &fees->closing); 130 } 131 132 133 void 134 TALER_wire_fee_set_ntoh (struct TALER_WireFeeSet *fees, 135 const struct TALER_WireFeeSetNBOP *nbo) 136 { 137 TALER_amount_ntoh (&fees->wire, 138 &nbo->wire); 139 TALER_amount_ntoh (&fees->closing, 140 &nbo->closing); 141 } 142 143 144 int 145 TALER_global_fee_set_cmp (const struct TALER_GlobalFeeSet *f1, 146 const struct TALER_GlobalFeeSet *f2) 147 { 148 int ret; 149 150 ret = TALER_amount_cmp (&f1->history, 151 &f2->history); 152 if (0 != ret) 153 return ret; 154 ret = TALER_amount_cmp (&f1->account, 155 &f2->account); 156 if (0 != ret) 157 return ret; 158 ret = TALER_amount_cmp (&f1->purse, 159 &f2->purse); 160 if (0 != ret) 161 return ret; 162 return 0; 163 } 164 165 166 int 167 TALER_wire_fee_set_cmp (const struct TALER_WireFeeSet *f1, 168 const struct TALER_WireFeeSet *f2) 169 { 170 int ret; 171 172 ret = TALER_amount_cmp (&f1->wire, 173 &f2->wire); 174 if (0 != ret) 175 return ret; 176 ret = TALER_amount_cmp (&f1->closing, 177 &f2->closing); 178 if (0 != ret) 179 return ret; 180 return 0; 181 } 182 183 184 enum GNUNET_GenericReturnValue 185 TALER_denom_fee_check_currency ( 186 const char *currency, 187 const struct TALER_DenomFeeSet *fees) 188 { 189 if (GNUNET_YES != 190 TALER_amount_is_currency (&fees->withdraw, 191 currency)) 192 { 193 GNUNET_break (0); 194 return GNUNET_NO; 195 } 196 if (GNUNET_YES != 197 TALER_amount_is_currency (&fees->deposit, 198 currency)) 199 { 200 GNUNET_break (0); 201 return GNUNET_NO; 202 } 203 if (GNUNET_YES != 204 TALER_amount_is_currency (&fees->refresh, 205 currency)) 206 { 207 GNUNET_break (0); 208 return GNUNET_NO; 209 } 210 if (GNUNET_YES != 211 TALER_amount_is_currency (&fees->refund, 212 currency)) 213 { 214 GNUNET_break (0); 215 return GNUNET_NO; 216 } 217 return GNUNET_OK; 218 } 219 220 221 /** 222 * Dump character in the low range into @a buf 223 * following RFC 8785. 224 * 225 * @param[in,out] buf buffer to modify 226 * @param val value to dump 227 */ 228 static void 229 lowdump (struct GNUNET_Buffer *buf, 230 unsigned char val) 231 { 232 char scratch[7]; 233 234 switch (val) 235 { 236 case 0x8: 237 GNUNET_buffer_write (buf, 238 "\\b", 239 2); 240 break; 241 case 0x9: 242 GNUNET_buffer_write (buf, 243 "\\t", 244 2); 245 break; 246 case 0xA: 247 GNUNET_buffer_write (buf, 248 "\\n", 249 2); 250 break; 251 case 0xC: 252 GNUNET_buffer_write (buf, 253 "\\f", 254 2); 255 break; 256 case 0xD: 257 GNUNET_buffer_write (buf, 258 "\\r", 259 2); 260 break; 261 default: 262 GNUNET_snprintf (scratch, 263 sizeof (scratch), 264 "\\u%04x", 265 (unsigned int) val); 266 GNUNET_buffer_write (buf, 267 scratch, 268 6); 269 break; 270 } 271 } 272 273 274 size_t 275 TALER_rfc8785encode (char **inp) 276 { 277 struct GNUNET_Buffer buf = { 0 }; 278 size_t left = strlen (*inp) + 1; 279 size_t olen; 280 char *in = *inp; 281 const char *pos = in; 282 283 GNUNET_buffer_prealloc (&buf, 284 left + 40); 285 buf.warn_grow = 0; /* disable, + 40 is just a wild guess */ 286 while (1) 287 { 288 int mbl = u8_mblen ((unsigned char *) pos, 289 left); 290 unsigned char val; 291 292 if (0 == mbl) 293 break; 294 val = (unsigned char) *pos; 295 if ( (1 == mbl) && 296 (val <= 0x1F) ) 297 { 298 /* Should not happen, as input is produced by 299 * JSON stringification */ 300 GNUNET_break (0); 301 lowdump (&buf, 302 val); 303 } 304 else if ( (1 == mbl) && ('\\' == *pos) ) 305 { 306 switch (*(pos + 1)) 307 { 308 case '\\': 309 mbl = 2; 310 GNUNET_buffer_write (&buf, 311 pos, 312 mbl); 313 break; 314 case 'u': 315 { 316 unsigned int num; 317 uint32_t n32; 318 unsigned char res[8]; 319 size_t rlen; 320 321 GNUNET_assert ( (1 == 322 sscanf (pos + 2, 323 "%4x", 324 &num)) || 325 (1 == 326 sscanf (pos + 2, 327 "%4X", 328 &num)) ); 329 mbl = 6; 330 n32 = (uint32_t) num; 331 rlen = sizeof (res); 332 u32_to_u8 (&n32, 333 1, 334 res, 335 &rlen); 336 if ( (1 == rlen) && 337 (res[0] <= 0x1F) ) 338 { 339 lowdump (&buf, 340 res[0]); 341 } 342 else 343 { 344 GNUNET_buffer_write (&buf, 345 (const char *) res, 346 rlen); 347 } 348 } 349 break; 350 default: 351 mbl = 2; 352 GNUNET_buffer_write (&buf, 353 pos, 354 mbl); 355 break; 356 } 357 } 358 else 359 { 360 GNUNET_buffer_write (&buf, 361 pos, 362 mbl); 363 } 364 left -= mbl; 365 pos += mbl; 366 } 367 368 /* 0-terminate buffer */ 369 GNUNET_buffer_write (&buf, 370 "", 371 1); 372 GNUNET_free (in); 373 *inp = GNUNET_buffer_reap (&buf, 374 &olen); 375 return olen; 376 } 377 378 379 /** 380 * Hash normalized @a j JSON object or array and 381 * store the result in @a hc. 382 * 383 * @param j JSON to hash 384 * @param[out] hc where to write the hash 385 */ 386 void 387 TALER_json_hash (const json_t *j, 388 struct GNUNET_HashCode *hc) 389 { 390 char *cstr; 391 size_t clen; 392 393 cstr = json_dumps (j, 394 JSON_COMPACT | JSON_SORT_KEYS); 395 GNUNET_assert (NULL != cstr); 396 clen = TALER_rfc8785encode (&cstr); 397 GNUNET_CRYPTO_hash (cstr, 398 clen, 399 hc); 400 GNUNET_free (cstr); 401 } 402 403 404 char ** 405 TALER_words_split (const char *command, 406 const char **extra_args) 407 { 408 unsigned int i = 0; 409 unsigned int j = 0; 410 unsigned int n = 0; 411 char **res = NULL; 412 413 /* Result is always NULL-terminated */ 414 GNUNET_array_append (res, n, NULL); 415 416 /* Split command into words */ 417 while (1) 418 { 419 char *c; 420 421 /* Skip initial whitespace before word */ 422 while (' ' == command[i]) 423 i++; 424 425 /* Start of new word */ 426 j = i; 427 428 /* Scan to end of word */ 429 while ( (0 != command[j]) && (' ' != command[j]) ) 430 j++; 431 432 /* No new word found */ 433 if (i == j) 434 break; 435 436 /* Append word to result */ 437 c = GNUNET_malloc (j - i + 1); 438 memcpy (c, &command[i], j - i); 439 c[j - i] = 0; 440 res[n - 1] = c; 441 GNUNET_array_append (res, n, NULL); 442 443 /* Continue at end of word */ 444 i = j; 445 } 446 447 /* Append extra args */ 448 if (NULL != extra_args) 449 { 450 for (const char **m = extra_args; *m; m++) 451 { 452 res[n - 1] = GNUNET_strdup (*m); 453 GNUNET_array_append (res, 454 n, 455 NULL); 456 } 457 } 458 459 return res; 460 } 461 462 463 void 464 TALER_words_destroy (char **args) 465 { 466 if (NULL == args) 467 return; 468 for (char **m = args; *m; m++) 469 { 470 GNUNET_free (*m); 471 *m = NULL; 472 } 473 GNUNET_free (args); 474 } 475 476 477 bool 478 TALER_is_slug (const char *slug) 479 { 480 const unsigned char *p; 481 482 if ('\0' == slug[0]) 483 return false; 484 485 /* Reject special path components */ 486 if (0 == strcmp (slug, ".") || 487 0 == strcmp (slug, "..")) 488 return false; 489 490 for (p = (const unsigned char *) slug; '\0' != *p; p++) 491 { 492 unsigned char c = *p; 493 494 if (isalnum (c)) 495 continue; 496 497 switch (c) 498 { 499 case '-': 500 case '_': 501 case '.': 502 case ':': 503 /* Note: could also allow '~' in principle, is on safe list! */ 504 continue; 505 default: 506 return false; 507 } 508 } 509 510 return true; 511 } 512 513 514 #ifdef __APPLE__ 515 char * 516 strchrnul (const char *s, 517 int c) 518 { 519 char *value; 520 value = strchr (s, 521 c); 522 if (NULL == value) 523 value = &s[strlen (s)]; 524 return value; 525 } 526 527 528 #endif 529 530 531 /* end of util.c */